41
Real World Dependency Injection Stephan Hochdörfer, bitExpert AG "Dependency Injection is a key element of agile architecture" Ward Cunningham

Real world dependency injection - DPC10

Embed Size (px)

Citation preview

Page 1: Real world dependency injection - DPC10

Real World Dependency InjectionStephan Hochdörfer, bitExpert AG

"Dependency Injection is a key element of agile architecture"

Ward Cunningham

Page 2: Real world dependency injection - DPC10

Agenda

1. About me

2. What is Dependency Injection?

3. Real World examples

4. Pros & Cons

5. Questions

Page 3: Real world dependency injection - DPC10

About me

Stephan Hochdörfer, bitExpert AG

Department Manager Research Labs

enjoying PHP since 1999

[email protected]

@shochdoerfer

Page 4: Real world dependency injection - DPC10

What is Dependency Injection?

What is Dependency?

Page 5: Real world dependency injection - DPC10

What is Dependency Injection?

What is Dependency?

Application Layer Data Access layer Business logic layer ...

External components Framework classes Webservices ...

Page 6: Real world dependency injection - DPC10

What is Dependency Injection?

Why are Dependencies bad?

Page 7: Real world dependency injection - DPC10

What is Dependency Injection?

Why are Dependencies bad?

„new“ is evil!

Page 8: Real world dependency injection - DPC10

What is Dependency Injection?

Why are Dependencies bad?

Tightly coupled code

Hard to re-use components

Hard to test components, no isolation

Page 9: Real world dependency injection - DPC10

What is Dependency Injection?

Requiredclass

Mainclass

Simple Dependency

Page 10: Real world dependency injection - DPC10

What is Dependency Injection?

Requiredclass

Mainclass

Requiredclass

Requiredclass

Complex Dependency

Page 11: Real world dependency injection - DPC10

What is Dependency Injection?

Requiredclass

Mainclass

Requiredclass

Requiredclass

Database

Externalresource

Requiredclass

Requiredclass

Webservice

Very complex Dependency

Page 12: Real world dependency injection - DPC10

What is Dependency Injection?

Requiredclass

Mainclass

Requiredclass

Requiredclass

Database

Externalresource

Requiredclass

Requiredclass

Webservice

Very complex Dependency

Page 13: Real world dependency injection - DPC10

What is Dependency Injection?

Requiredclass

Mainclass

Requiredclass

Requiredclass

Database

Externalresource

Requiredclass

Requiredclass

Webservice

Very complex Dependency

Page 14: Real world dependency injection - DPC10

What is Dependency Injection?

How to Manage Dependencies?

Page 15: Real world dependency injection - DPC10

What is Dependency Injection?

How to Manage Dependencies?

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

Page 16: Real world dependency injection - DPC10

What is Dependency Injection?

How to Manage Dependencies?

Simple Container vs. Full stacked Framework

Page 17: Real world dependency injection - DPC10

What is Dependency Injection?

What is Dependency Injection?

Page 18: Real world dependency injection - DPC10

What is Dependency Injection?

What is Dependency Injection?

Consumer

Page 19: Real world dependency injection - DPC10

What is Dependency Injection?

What is Dependency Injection?

Consumer Dependencies

Page 20: Real world dependency injection - DPC10

What is Dependency Injection?

What is Dependency Injection?

Consumer Dependencies Container

Page 21: Real world dependency injection - DPC10

What is Dependency Injection?

What is Dependency Injection?

Consumer Dependencies Container

Page 22: Real world dependency injection - DPC10

What is Dependency Injection?

Types of Dependency Injection

Type 1: Constructor injection

<?php

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

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

}}?>

Page 23: Real world dependency injection - DPC10

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;

}}?>

Page 24: Real world dependency injection - DPC10

What is Dependency Injection?

Types of Dependency Injection

Type 3: Interface injection

<?php

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

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

}}?>

Page 25: Real world dependency injection - DPC10

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; }}?>

Page 26: Real world dependency injection - DPC10

What is Dependency Injection?

Configuration Types

Type 1: Annotations

<?php

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

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

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

Page 27: Real world dependency injection - DPC10

What is Dependency Injection?

Configuration Types

Type 2: External configuration via XML

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

Page 28: Real world dependency injection - DPC10

What is Dependency Injection?

Configuration Types

Type 2: External configuration via YAML

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

Page 29: Real world dependency injection - DPC10

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");

}?>

Page 30: Real world dependency injection - DPC10

What is Dependency Injection?

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

Page 31: Real world dependency injection - DPC10

Real world examples

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

Robert C. Martin

Page 32: Real world dependency injection - DPC10

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

}}?>

Page 33: Real world dependency injection - DPC10

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

Page 34: Real world dependency injection - DPC10

Real World examples

One class, multiple configurations II<?phpclass Promio_Action_Account_Auth extends bF_Mvc_Action_AFormAction {

private $oAccountManager;private $iType;

public function __construct(Promio_Service_IAccountManager $poAccountManager) {$this->oAccountManager = $poAccountManager;

}

public function setType($piType) {$this->iType = (int) $piType;

}

protected function processFormSubmission(bF_Bo_ABo $poBOFormBackingObject) {$oMaV = new bF_Mvc_ModelAndView($this->getSuccessView(), true);try {

$poBOFormBackingObject->setType($this->iType);$this->oAccountManager->save($poBOFormBackingObject);

}catch(bF_Service_ServiceException $oException) {

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

}}?>

Page 35: Real world dependency injection - DPC10

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

Page 36: Real world dependency injection - DPC10

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

Page 37: Real world dependency injection - DPC10

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;

}}?>

Page 38: Real world dependency injection - DPC10

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) {}

}}?>

Page 39: Real world dependency injection - DPC10

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 Separation of glue code from business logic

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

Page 40: Real world dependency injection - DPC10

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↔

Page 41: Real world dependency injection - DPC10

http://joind.in/1553