Real World Dependency Injection - PFCongres 2010

Preview:

Citation preview

Real World Dependency InjectionStephan Hochdörfer, bitExpert AG

"Dependency Injection is a key element of agile architecture"

Ward Cunningham

About me

Founder of bitExpert AG, Mannheim

Field of duty Department Manager of Research Labs Head of Development for bitFramework

Focusing on PHP Generative Programming

Contact me @shochdoerfer S.Hochdoerfer@bitExpert.de

Agenda

1. What is Dependency Injection?

2. Real World examples

3. Pros & Cons

4. Questions

What is Dependency Injection?

"Dependency Injection is probably one of the most dead simple design pattern [...] but it is also one of the most difficult one to

explain well."Fabien Potencier

What is Dependency Injection?

"Dependency Injection is probably one of the most dead simple design pattern [...] but it is also one of the most difficult one to

explain well."Fabien Potencier

What is Dependency Injection?

What is Dependency Injection?

Popularized by Martin Fowler in 2004

Technique for supplying external dependencies to a component

Main idea: Ask for things, do not look for things!

Three elements Dependant / Consumer Dependencies, e.g. service objects Injector / Container

What is Dependency Injection?

Problems of Dependencies

Code is very tightly coupled Hard to re-use code Hard to test code, no isolation possible

Difficult to maintain What is affected when code changes? Boilerplate configuration code within Business logic

What is Dependency Injection?

Requiredclass

Mainclass

Simple Dependency

What is Dependency Injection?

Requiredclass

Mainclass

Requiredclass

Requiredclass

Complex Dependency

What is Dependency Injection?

Requiredclass

Mainclass

Requiredclass

Requiredclass

Database

Externalresource

Requiredclass

Requiredclass

Webservice

Very complex Dependency

What is Dependency Injection?

Requiredclass

Mainclass

Requiredclass

Requiredclass

Database

Externalresource

Requiredclass

Requiredclass

Webservice

Very complex Dependency

What is Dependency Injection?

Requiredclass

Mainclass

Requiredclass

Requiredclass

Database

Externalresource

Requiredclass

Requiredclass

Webservice

Very complex Dependency

What is Dependency Injection?

How to Manage Dependencies?

What is Dependency Injection?

How to Manage Dependencies?

You don`t need to. The Framework does it all!

What is Dependency Injection?

Types of Dependency Injection

Type 1: Interface injection

<?php

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

public function setApplicationContext(IApplicationContext $poCtx) {$this->oCtx = $poCtx;

}}?>

What is Dependency Injection?

Types of Dependency Injection

Type 2: Setter injection

<?php

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

public function setSampleDao(ISampleDao $poSampleDao) {$this->oSampleDao = $poSamleDao;

}}?>

What is Dependency Injection?

Types of Dependency Injection

Type 3: Constructor injection

<?php

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

public function __construct(ISampleDao $poSampleDao) {$this->oSampleDao = $poSamleDao;

}}?>

What is Dependency Injection?

Configuration Types

Type 1: Annotations

<?php

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

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

$this->oSampleDao = $poSamleDao; }}?>

What is Dependency Injection?

Configuration Types

Type 2: External configuration via XML, JSON, YAML, ...

<?xml version="1.0" encoding="UTF-8" ?><beans xmlns="http://www.bitexpert.de/schema"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.bitexpert.de/schema/

http://www.bitexpert.de/schema/bitFramework-beans.xsd">

<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>

What is Dependency Injection?

Configuration Types

Type 3: PHP Configuration

<?phpclass BeanCache extends bF_Beanfactory_Container_PHP_ACache {

protected function createSampleDao() {$oBean = new SampleDao('app_sample', 'iSampleId', 'BoSample');return array("oBean" => $oBean, "bSingleton" => "1");

}

protected function createMySampleService() {$oBean = new MySampleService($this->getBean('SampleDao'));return array("oBean" => $oBean, "bSingleton" => "1");

}?>

Agenda

1. What is Dependency Injection?

2. Real World examples

3. Pros & Cons

4. Questions

Real world examples

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

Robert C. Martin

Real World examples

Unittesting made easy

<?phprequire_once 'PHPUnit/Framework.php';

class ServiceTest extends PHPUnit_Framework_TestCase { public function testSampleService() { $oSampleDao = $this->getMock('ISampleDao');

// run test case$oService = new MySampleService($oSampleDao);$bReturn = $oService->doWork();

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

}}?>

Real World examples

One class, multiple configurations

<?xml version="1.0" encoding="UTF-8" ?><beans xmlns="http://www.bitexpert.de/schema"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.bitexpert.de/schema/

http://www.bitexpert.de/schema/bitFramework-beans.xsd">

<bean id="ExportLive" class="MyApp_Service_ExportManager"><constructor-arg ref="DAOPageLive" />

</bean>

<bean id="ExportWorking" class="MyApp_Service_ExportManager"><constructor-arg ref="DAOPageWorking" />

</bean>

</beans>

Implementation

Live Working

Real World examples

Mocking external services

Connector WebserviceConsumer

<?xml version="1.0" encoding="UTF-8" ?><beans xmlns="http://www.bitexpert.de/schema"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.bitexpert.de/schema/

http://www.bitexpert.de/schema/bitFramework-beans.xsd">

<bean id="Consumer" class="MyApp_Service_Consumer"><constructor-arg ref="Connector" />

</bean>

</beans>

IConnector interface

Real World examples

Mocking external services

alternativeConnector

Localfilesystem

Consumer

<?xml version="1.0" encoding="UTF-8" ?><beans xmlns="http://www.bitexpert.de/schema"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.bitexpert.de/schema/

http://www.bitexpert.de/schema/bitFramework-beans.xsd">

<bean id="Consumer" class="MyApp_Service_Consumer"><constructor-arg ref="AltConnector" />

</bean>

</beans>

IConnector interface

Real World examples

Clean, readable code

<?php

class Promio_Action_News_Delete extends bF_Mvc_Action_AAction {/** * @var Promio_Service_INewsManager */private $oNewsManager;

public function __construct(Promio_Service_INewsManager $poNewsManager) {$this->oNewsManager = $poNewsManager;

}

protected function execute(bF_Mvc_Request $poRequest) {try {

$this->oNewsManager->delete((int) $poRequest->getVar('iNewsId'));}catch(bF_Service_ServiceException $oException) {}

$oMaV = new bF_Mvc_ModelAndView($this->getSuccessView(), true);return $oMaV;

}}?>

Real World examples

No framework dependency

<?php

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

public function __construct(ISampleDao $poSampleDao) {$this->oSampleDao = $poSamleDao;

}

public function getSample($piSampleId) {try { return $this->oSampleDao->readByPrimaryKey((int) $piSampleId);}catch(DaoException $oException) {}

}}?>

Real World examples

Cache, Cache, Cache!

XML no Caching XML with Caching PHP PHP compiled

0

20

40

60

80

100

120

140

160

180

Requests per Second meassured via Apache HTTP server benchmarking tool

Agenda

1. What is Dependency Injection?

2. Real World Examples

3. Pros & Cons

4. Questions

Pros & Cons

Benefits

Good for agile development Reducing amount of code Helpful for Unit testing

Loose coupling Least intrusive mechanism Switching implementations by changing configuration

Clean view on the code Separate configuration from code Getting rid of boilerpate configuration code

Pros & Cons

Cons

To many different implementations, no standard today! 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, …

No JSR 330 for PHP

Simple Containers vs. fully-stacked Framework No dependency from application to Container!

Developers need to be aware of configuration runtime↔

Agenda

1. What is Dependency Injection?

2. Pros & Cons

3. Real World examples

4. Questions

Recommended