2. Dependency Injection – Was, wie warum?
Über mich
Stephan Hochdörfer
Head of IT der bitExpert AG, Mannheim
PHP`ler seit 1999
S.Hochdoerfer@bitExpert.de
@shochdoerfer
7. Dependency Injection – Was, wie warum?
Dependency Injection
"[...] zur Laufzeit die Abhängigkeiten
eines Objekts diesem von einem
anderen Objekt als Referenzen zur
Verfügung gestellt werden."
(Wikipedia)
21. <?php
class 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')
);
}
}
Dependency Injection – Was, wie warum?
„new“ is evil!
22. Dependency Injection – Was, wie warum?
„new“ is evil!
<?php
class 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')
);
}
}
23. "High-level modules should not
depend on low-level modules.
Both should depend on abstractions."
Robert C. Martin
Dependency Injection – Was, wie warum?
24. Dependency Injection – Was, wie warum?
„new“ is evil!
<?php
class 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')
);
}
}
25. Wie verwaltet man Dependencies?
Dependency Injection – Was, wie warum?
26. Wie verwaltet man Dependencies?
Simple Container vs. Full stacked
DI Framework
Dependency Injection – Was, wie warum?
27. Der Container nimmt uns die Arbeit ab!
Dependency Injection – Was, wie warum?
45. Unittesting einfach gemacht
<?php
require_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);
}
}
Dependency Injection – Was, wie warum?
47. Eine Klasse, mehrfache Ausprägung
Page ExporterPage Exporter
Released / Published
Pages
Released / Published
Pages
Workingcopy
Pages
Workingcopy
Pages
Dependency Injection – Was, wie warum?
48. Eine Klasse, mehrfache Ausprägung
<?php
abstract class PageExporter {
protected function setPageDao(IPageDao $pageDao) {
$this->pageDao = $pageDao;
}
}
Dependency Injection – Was, wie warum?
49. Eine Klasse, mehrfache Ausprägung
<?php
abstract class PageExporter {
protected function setPageDao(IPageDao $pageDao) {
$this->pageDao = $pageDao;
}
}
Zur Erinnerung:
Der Vertrag!
Dependency Injection – Was, wie warum?
50. Eine Klasse, mehrfache Ausprägung
<?php
class PublishedPageExporter extends PageExporter {
public function __construct() {
$this->setPageDao(new PublishedPageDao());
}
}
class WorkingCopyPageExporter extends PageExporter {
public function __construct() {
$this->setPageDao(new WorkingCopyPageDao());
}
}
Dependency Injection – Was, wie warum?
51. "Only deleted code is good code!"
Oliver Gierke
Eine Klasse, mehrfache Ausprägung
Dependency Injection – Was, wie warum?
52. Eine Klasse, mehrfache Ausprägung
<?php
class PageExporter {
public function __construct(IPageDao $pageDao) {
$this->pageDao = $pageDao;
}
}
Dependency Injection – Was, wie warum?
66. Pimple – Erste Schritte
Dependency Injection – Was, wie warum?
<?php
class TalkService {
public function __construct() {
}
public function getTalks() {
}
}
67. Pimple – Erste Schritte
Dependency Injection – Was, wie warum?
<?php
require_once '/path/to/Pimple.php';
require_once '/path/to/TalkService.php';
// create the Container
$container = new Pimple();
// define talkService object in container
$container['talkService'] = function ($c) {
return new TalkService();
};
// instantiate talkService from container
$talkService = $container['talkService'];
68. Pimple – Constructor Injection
Dependency Injection – Was, wie warum?
<?php
interface GenericRepository {
public function readTalks();
}
class TalkRepository implements GenericRepository {
public function readTalks() {
}
}
class TalkService {
public function __construct(TalkRepository $repo) {
}
public function getTalks() {
}
}
69. Pimple – Constructor Injection
Dependency Injection – Was, wie warum?
<?php
require_once '/path/to/Pimple.php';
require_once '/path/to/TalkService.php';
// create the Container
$container = new Pimple();
// define services in container
$container['talkRepository'] = function ($c) {
return new TalkRepository();
};
$container['talkService'] = function ($c) {
return new TalkService($c['talkRepository']);
};
// instantiate talkService from container
$talkService = $container['talkService'];
70. Pimple – Setter Injection
Dependency Injection – Was, wie warum?
<?php
class Logger {
public function doLog($logMsg) {
}
}
class TalkService {
public function __construct(TalkRepository $repo) {
}
public function setLogger(Logger $logger) {
}
public function getTalks() {
}
}
71. Pimple – Setter Injection
Dependency Injection – Was, wie warum?
<?php
require_once '/path/to/Pimple.php';
require_once '/path/to/TalkService.php';
// create the Container
$container = new Pimple();
// define services in container
$container['logger'] = function ($c) {
return new Logger();
};
$container['talkRepository'] = function ($c) {
return new TalkRepository();
};
$container['talkService'] = function ($c) {
$service = new TalkService($c['talkRepository']);
$service->setLogger($c['logger']);
return $service;
};
// instantiate talkService from container
$talkService = $container['talkService'];
73. ZendDi – Erste Schritte
Dependency Injection – Was, wie warum?
<?php
namespace Acme;
class TalkService {
public function __construct() {
}
public function getTalks() {
}
}
74. ZendDi – Erste Schritte
Dependency Injection – Was, wie warum?
<?php
$di = new ZendDiDi();
$service = $di->get('AcmeTalkService');
$service->getTalks();
75. ZendDi – Constructor Injection
Dependency Injection – Was, wie warum?
<?php
namespace Acme;
interface GenericRepository {
public function readTalks();
}
class TalkRepository implements GenericRepository {
public function readTalks() {
}
}
class TalkService {
public function __construct(TalkRepository $repo) {
}
public function getTalks() {
}
}
76. ZendDi – Constructor Injection
Dependency Injection – Was, wie warum?
<?php
$di = new ZendDiDi();
$service = $di->get('AcmeTalkService');
$service->getTalks();
77. ZendDi – Setter Injection
Dependency Injection – Was, wie warum?
<?php
namespace Acme;
class Logger {
public function doLog($logMsg) {
}
}
class TalkService {
public function __construct(TalkRepository $repo) {
}
public function setLogger(Logger $logger) {
}
public function getTalks() {
}
}
79. ZendDi – Interface Injection
Dependency Injection – Was, wie warum?
<?php
namespace Acme;
class Logger {
public function doLog($logMsg) {
}
}
interface LoggerAware {
public function setLogger(Logger $logger);
}
class TalkService implements LoggerAware {
public function __construct(TalkRepository $repo) {
}
public function setLogger(Logger $logger) {
}
public function getTalks() {
}
}
80. ZendDi – Interface Injection
Dependency Injection – Was, wie warum?
<?php
$di = new ZendDiDi();
$service = $di->get('AcmeTalkService');
$service->getTalks();
81. ZendDi – Grundsätzliches
Dependency Injection – Was, wie warum?
<?php
$di = new ZendDiDi();
$service = $di->get('AcmeTalkService');
var_dump($service);
$service2 = $di->get('AcmeTalkService');
var_dump($service2); // same instance as $service
$service3 = $di->get(
'AcmeTalkService',
array(
'repo' => new AcmeTalkRepository()
)
);
82. ZendDi – Builder Definition
Dependency Injection – Was, wie warum?
<?php
// describe dependency
$dep = new ZendDiDefinitionBuilderPhpClass();
$dep->setName('AcmeTalkRepository');
// describe class
$class = new ZendDiDefinitionBuilderPhpClass();
$class->setName('AcmeTalkService');
// add injection method
$im = new ZendDiDefinitionBuilderInjectionMethod();
$im->setName('__construct');
$im->addParameter('repo', 'AcmeTalkRepository');
$class->addInjectionMethod($im);
// configure builder
$builder = new ZendDiDefinitionBuilderDefinition();
$builder->addClass($dep);
$builder->addClass($class);
83. ZendDi – Builder Definition
Dependency Injection – Was, wie warum?
<?php
// add to Di
$defList = new ZendDiDefinitionList($builder);
$di = new ZendDiDi($defList);
$service = $di->get('AcmeTalkService');
var_dump($service);
85. Symfony2
Dependency Injection – Was, wie warum?
<?php
namespace AcmeTalkBundleController;
use SymfonyBundleFrameworkBundleControllerController;
use SensioBundleFrameworkExtraBundleConfigurationRoute;
use SensioBundleFrameworkExtraBundleConfigurationTemplate;
class TalkController extends Controller {
/**
* @Route("/", name="_talk")
* @Template()
*/
public function indexAction() {
$service = $this->get('acme.talk.service');
return array();
}
}
86. Symfony2 – Konfigurationsdatei
Dependency Injection – Was, wie warum?
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services
http://symfony.com/schema/dic/services/services-1.0.xsd">
</container>
File services.xml in src/Acme/DemoBundle/Resources/config