69
Real World Dependency Injection Stephan Hochdörfer, bitExpert AG

Real World Dependency Injection - phpday

Embed Size (px)

DESCRIPTION

 

Citation preview

Page 1: Real World Dependency Injection - phpday

Real World Dependency Injection

Stephan Hochdörfer, bitExpert AG

Page 2: Real World Dependency Injection - phpday

Real World Dependency Injection

About me

Stephan Hochdörfer, bitExpert AG

Department Manager Research Labs

enjoying PHP since 1999

[email protected]

@shochdoerfer

Page 3: Real World Dependency Injection - phpday

Real World Dependency Injection

What are Dependencies?

Page 4: Real World Dependency Injection - phpday

What are Dependencies?

Application

Framework add. Libraries

Real World Dependency Injection

Page 5: Real World Dependency Injection - phpday

What are Dependencies?

Controller

Service / Model

Datastore(s)

UtilsPHP extensions

Real World Dependency Injection

Page 6: Real World Dependency Injection - phpday

Are Dependencies bad?

Real World Dependency Injection

Page 7: Real World Dependency Injection - phpday

Are Dependencies bad?

Dependencies are not bad! They are useful!

Real World Dependency Injection

Page 8: Real World Dependency Injection - phpday

Are Dependencies bad?

Hard-coded dependencies are bad!

Real World Dependency Injection

Page 9: Real World Dependency Injection - phpday

Tightly coupled code

Real World Dependency Injection

Page 10: Real World Dependency Injection - phpday

No reuse of components

Real World Dependency Injection

Page 11: Real World Dependency Injection - phpday

No isolation, not testable!

Real World Dependency Injection

Page 12: Real World Dependency Injection - phpday

Real World Dependency Injection

Development gets overcomplicated!

Page 13: Real World Dependency Injection - phpday

s

Real World Dependency Injection

„new“ is evil!

Page 14: Real World Dependency Injection - phpday

<?phpclass DeletePage extends Mvc_Action_AAction {

private $pageManager;

public function __construct() {$this->pageManager = new PageManager();

}

protected function execute(Mvc_Request $request) {$this->pageManager->delete(

(int) $request->get('pageId'));

}}

Real World Dependency Injection

„new“ is evil!

Page 15: Real World Dependency Injection - phpday

Real World Dependency Injection

„new“ is evil!

<?phpclass DeletePage extends Mvc_Action_AAction {

private $pageManager;

public function __construct(PageManager $pm) {$this->pageManager = $pm;

}

protected function execute(Mvc_Request $request) {$this->pageManager->delete(

(int) $request->get('pageId'));

}}

Page 16: Real World Dependency Injection - phpday

"High-level modules should not depend on low-level modules.

Both should depend on abstractions."

Robert C. Martin

Real World Dependency Injection

Page 17: Real World Dependency Injection - phpday

Interfaces act as contracts

Real World Dependency Injection

Page 18: Real World Dependency Injection - phpday

Real World Dependency Injection

„new“ is evil!

<?phpclass DeletePage extends Mvc_Action_AAction {

private $pageManager;

public function __construct(IPageManager $pm) {$this->pageManager = $pm;

}

protected function execute(Mvc_Request $request) {$this->pageManager->delete(

(int) $request->get('pageId'));

}}

Page 19: Real World Dependency Injection - phpday

How to Manage Dependencies?

Real World Dependency Injection

Page 20: Real World Dependency Injection - phpday

Manually resolve dependencies?

Real World Dependency Injection

Page 21: Real World Dependency Injection - phpday

Automatic wiring required!

Simple Container vs. Full stacked DI Framework

Real World Dependency Injection

Page 22: Real World Dependency Injection - phpday

What is Dependency Injection?

Real World Dependency Injection

Page 23: Real World Dependency Injection - phpday

What is Dependency Injection?

Consumer

Real World Dependency Injection

Page 24: Real World Dependency Injection - phpday

What is Dependency Injection?

Consumer Dependencies

Real World Dependency Injection

Page 25: Real World Dependency Injection - phpday

What is Dependency Injection?

Consumer Dependencies Container

Real World Dependency Injection

Page 26: Real World Dependency Injection - phpday

What is Dependency Injection?

Consumer Dependencies Container

Real World Dependency Injection

Page 27: Real World Dependency Injection - phpday

How to inject a Dependency?

Real World Dependency Injection

Page 28: Real World Dependency Injection - phpday

Constructor Injection

<?php

class MySampleService implements IMySampleService { /** * @var ISampleDao */ private $sampleDao;

public function __construct(ISampleDao $sampleDao) {$this->sampleDao = $sampleDao;

}}

Real World Dependency Injection

Page 29: Real World Dependency Injection - phpday

Setter injection<?php

class MySampleService implements IMySampleService { /** * @var ISampleDao */ private $sampleDao;

public function setSampleDao(ISampleDao $sampleDao){$this->sampleDao = $sampleDao;

}}

Real World Dependency Injection

Page 30: Real World Dependency Injection - phpday

Interface injection<?php

interface IApplicationContextAware { public function setCtx(IApplicationContext $ctx);}

Real World Dependency Injection

Page 31: Real World Dependency Injection - phpday

Interface injection<?php

class MySampleService implements IMySampleService,IApplicationContextAware { /** * @var IApplicationContext */ private $ctx;

public function setCtx(IApplicationContext $ctx) {$this->ctx = $ctx;

}}

Real World Dependency Injection

Page 32: Real World Dependency Injection - phpday

Real World Dependency Injection

How to wire it all up?

Page 33: Real World Dependency Injection - phpday

Real World Dependency Injection

Annotation based wiring<?php

class MySampleService implements IMySampleService { private $sampleDao;

/** * @Inject */ public function __construct(ISampleDao $sampleDao) {

$this->sampleDao = $sampleDao; }}

Page 34: Real World Dependency Injection - phpday

Real World Dependency Injection

Annotation based wiring<?php

class MySampleService implements IMySampleService { private $sampleDao;

/** * @Inject * @Named('TheSampleDao') */ public function __construct(ISampleDao $sampleDao) {

$this->sampleDao = $sampleDao; }}

Page 35: Real World Dependency Injection - phpday

External configuration - XML

<?xml version="1.0" encoding="UTF-8" ?><beans>

<bean id="SampleDao" class="SampleDao"><constructor-arg value="app_sample" /><constructor-arg value="iSampleId" /><constructor-arg value="BoSample" />

</bean>

<bean id="SampleService" class="MySampleService"><constructor-arg ref="SampleDao" />

</bean></beans>

Real World Dependency Injection

Page 36: Real World Dependency Injection - phpday

External configuration - YAML

services: SampleDao: class: SampleDao arguments: ['app_sample', 'iSampleId', 'BoSample'] SampleService: class: SampleService arguments: [@SampleDao]

Real World Dependency Injection

Page 37: Real World Dependency Injection - phpday

External configuration - PHP<?phpclass BeanCache extends Beanfactory_Container_PHP {

protected function createSampleDao() {$oBean = new SampleDao('app_sample',

'iSampleId', 'BoSample');return $oBean;

}

protected function createMySampleService() {$oBean = new MySampleService(

$this->getBean('SampleDao'));return $oBean;

}}

Real World Dependency Injection

Page 38: Real World Dependency Injection - phpday

Real World Dependency Injection

Ready to unlock the door?

Page 39: Real World Dependency Injection - phpday

Unittesting made easy

Real World Dependency Injection

Page 40: Real World Dependency Injection - phpday

Unittesting made easy<?phprequire_once 'PHPUnit/Framework.php';

class ServiceTest extends PHPUnit_Framework_TestCase { public function testSampleService() {

// set up dependencies $sampleDao = $this->getMock('ISampleDao'); $service = new MySampleService($sampleDao);

// run test case$return = $service->doWork();

// check assertions$this->assertTrue($return);

}}

Real World Dependency Injection

Page 41: Real World Dependency Injection - phpday

One class, multiple configurations

Real World Dependency Injection

Page 42: Real World Dependency Injection - phpday

One class, multiple configurations

Page ExporterPage Exporter

Released / PublishedPages

Released / PublishedPages

WorkingcopyPages

WorkingcopyPages

Real World Dependency Injection

Page 43: Real World Dependency Injection - phpday

One class, multiple configurations<?phpabstract class PageExporter { protected function setPageDao(IPageDao $pageDao) { $this->pageDao = $pageDao; }}

Real World Dependency Injection

Page 44: Real World Dependency Injection - phpday

One class, multiple configurations<?phpabstract class PageExporter { protected function setPageDao(IPageDao $pageDao) { $this->pageDao = $pageDao; }}

Remember: The contract!

Real World Dependency Injection

Page 45: Real World Dependency Injection - phpday

One class, multiple configurations

<?phpclass PublishedPageExporter extends PageExporter { public function __construct() { $this->setPageDao(new PublishedPageDao()); }}

class WorkingCopyPageExporter extends PageExporter { public function __construct() { $this->setPageDao(new WorkingCopyPageDao()); }}

Real World Dependency Injection

Page 46: Real World Dependency Injection - phpday

"Only deleted code is good code!"Oliver Gierke

One class, multiple configurations

Real World Dependency Injection

Page 47: Real World Dependency Injection - phpday

One class, multiple configurations<?phpclass PageExporter { public function __construct(IPageDao $pageDao) { $this->pageDao = $pageDao; }}

Real World Dependency Injection

Page 48: Real World Dependency Injection - phpday

One class, multiple configurations<?xml version="1.0" encoding="UTF-8" ?><beans>

<bean id="ExportLive" class="PageExporter"><constructor-arg ref="PublishedPageDao" />

</bean>

<bean id="ExportWorking" class="PageExporter"><constructor-arg ref="WorkingCopyPageDao" />

</bean></beans>

Real World Dependency Injection

Page 49: Real World Dependency Injection - phpday

One class, multiple configurations

<?php

// create ApplicationContext instance$ctx = new ApplicationContext();

// retrieve live exporter$exporter = $ctx->getBean('ExportLive');

// retrieve working copy exporter$exporter = $ctx->getBean('ExportWorking');

Real World Dependency Injection

Page 50: Real World Dependency Injection - phpday

One class, multiple configurations II

Real World Dependency Injection

Page 51: Real World Dependency Injection - phpday

One class, multiple configurations II

http://editor.loc/page/[id]/headline/

http://editor.loc/page/[id]/content/

http://editor.loc/page/[id]/teaser/

Real World Dependency Injection

Page 52: Real World Dependency Injection - phpday

<?phpclass EditPart extends Mvc_Action_AFormAction {

private $pagePartsManager;private $type;

public function __construct(IPagePartsManager $pm) {$this->pagePartsManager = $pm;

}

public function setType($ptype) {$this->type = (int) $type;

}

protected function process(Bo_ABo $formBackObj) {}

}

One class, multiple configurations II

Real World Dependency Injection

Page 53: Real World Dependency Injection - phpday

One class, multiple configurations II<?xml version="1.0" encoding="UTF-8" ?><beans>

<bean id="EditHeadline" class="EditPart"><constructor-arg ref="PagePartDao" /><property name="Type" const="PType::Headline" />

</bean>

<bean id="EditContent" class="EditPart"><constructor-arg ref="PagePartDao" /><property name="Type" const="PType::Content" />

</bean>

</beans>

Real World Dependency Injection

Page 54: Real World Dependency Injection - phpday

Mocking external service access

Real World Dependency Injection

Page 55: Real World Dependency Injection - phpday

Mocking external service access

Booking serviceBooking service WS-Connector

WS-Connector WebserviceWebservice

Real World Dependency Injection

Page 56: Real World Dependency Injection - phpday

Mocking external service access

Booking serviceBooking service WS-Connector

WS-Connector WebserviceWebservice

Remember: The contract!

Real World Dependency Injection

Page 57: Real World Dependency Injection - phpday

Mocking external service access

Booking serviceBooking service FS-Connector

FS-Connector FilesystemFilesystem

Real World Dependency Injection

Page 58: Real World Dependency Injection - phpday

Mocking external service access

Booking serviceBooking service FS-Connector

FS-Connector FilesystemFilesystem

fullfills thecontract!

Real World Dependency Injection

Page 59: Real World Dependency Injection - phpday

Clean, readable code

Real World Dependency Injection

Page 60: Real World Dependency Injection - phpday

Clean, readable code<?phpclass DeletePage extends Mvc_Action_AAction {

private $pageManager;

public function __construct(IPageManager $pm) {$this->pageManager = $pm;

}

protected function execute(Mvc_Request $request) {$this->pageManager->delete(

(int) $request->get('pageId'));

return new ModelAndView($this->getSuccessView());}

}

Real World Dependency Injection

Page 61: Real World Dependency Injection - phpday

No framework dependency

Real World Dependency Injection

Page 62: Real World Dependency Injection - phpday

No framework dependency<?phpclass MySampleService implements IMySampleService { private $sampleDao;

public function __construct(ISampleDao $sampleDao) {$this->sampleDao = $sampleDao;

}

public function getSample($sampleId) {try { return $this->sampleDao->readById($sampleId);}catch(DaoException $exception) {}

}}

Real World Dependency Injection

Page 63: Real World Dependency Injection - phpday

Benefits

Loose coupling, reuse of components!

Real World Dependency Injection

Page 64: Real World Dependency Injection - phpday

Benefits

Can reduce the amount of code!

Real World Dependency Injection

Page 65: Real World Dependency Injection - phpday

Benefits

Helps developers to understand the code!

Real World Dependency Injection

Page 66: Real World Dependency Injection - phpday

Cons – No JSR330 for PHP

Bucket, Crafty, FLOW3, Imind_Context, PicoContainer, Pimple, Phemto,

Stubbles, Symfony 2.0, Sphicy, Solar, Substrate, XJConf, Yadif, Zend_Di (Proposal), Lion Framework, Spiral Framework, Xyster Framework, …

Real World Dependency Injection

Page 67: Real World Dependency Injection - phpday

Cons – Developers need mindshift

Configuration ↔ Runtime

Real World Dependency Injection

Page 68: Real World Dependency Injection - phpday

http://joind.in/3002

Page 69: Real World Dependency Injection - phpday

Image Creditshttp://www.sxc.hu/photo/1028452