2. Real World Dependency Injection
About me
Stephan Hochdörfer, bitExpert AG
Department Manager Research Labs
enjoying PHP since 1999
S.Hochdoerfer@bitExpert.de
@shochdoerfer
15. <?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')
);
}
}
Real World Dependency Injection
„new“ is evil!
16. Real World Dependency Injection
„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')
);
}
}
17. "High-level modules should not
depend on low-level modules.
Both should depend on
abstractions."
Robert C. Martin
Real World Dependency Injection
34. Real World Dependency Injection
Annotation based wiring
<?php
class MySampleService implements IMySampleService {
private $sampleDao;
/**
* @Inject
*/
public function __construct(ISampleDao $sampleDao)
{
$this->sampleDao = $sampleDao;
}
}
35. 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;
}
}
42. Unittesting made easy
<?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);
}
}
Real World Dependency Injection
44. One class, multiple configurations
Page ExporterPage Exporter
Released / Published
Pages
Released / Published
Pages
Real World Dependency Injection
45. One class, multiple configurations
Page ExporterPage Exporter
Released / Published
Pages
Released / Published
Pages
Workingcopy
Pages
Workingcopy
Pages
Real World Dependency Injection
46. One class, multiple configurations
<?php
abstract class PageExporter {
protected function setPageDao(IPageDao $pageDao) {
$this->pageDao = $pageDao;
}
}
Real World Dependency Injection
47. One class, multiple configurations
<?php
abstract class PageExporter {
protected function setPageDao(IPageDao $pageDao) {
$this->pageDao = $pageDao;
}
}
Remember:
The contract!
Real World Dependency Injection
48. One class, multiple configurations
<?php
class 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
49. "Only deleted code is good code!"
Oliver Gierke
One class, multiple configurations
Real World Dependency Injection
50. One class, multiple configurations
<?php
class PageExporter {
public function __construct(IPageDao $pageDao) {
$this->pageDao = $pageDao;
}
}
Real World Dependency Injection
51. 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
52. 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
53. One class, multiple configurations II
Page ExporterPage Exporter
Released / Published
Pages
Released / Published
Pages
Workingcopy
Pages
Workingcopy
Pages
Real World Dependency Injection
54. One class, multiple configurations II
Page ExporterPage Exporter
Released / Published
Pages
Released / Published
Pages
Workingcopy
Pages
Workingcopy
Pages
Real World Dependency Injection
HTMLHTML
55. One class, multiple configurations II
Page ExporterPage Exporter
Released / Published
Pages
Released / Published
Pages
Workingcopy
Pages
Workingcopy
Pages
Real World Dependency Injection
PDFPDFHTMLHTML
56. One class, multiple configurations II
<?xml version="1.0" encoding="UTF-8" ?>
<beans>
<bean id="ExportLive" class="PageExporter">
<constructor-arg ref="PublishedPageDao" />
<constructor-arg ref="HTMLExporter" />
</bean>
<bean id="ExportWorking" class="PageExporter">
<constructor-arg ref="WorkingCopyPageDao" />
<constructor-arg ref="PDFExporter" />
</bean>
</beans>
Real World Dependency Injection
58. One class, multiple configurations III
http://editor.loc/page/[id]/headline/
http://editor.loc/page/[id]/content/
http://editor.loc/page/[id]/teaser/
Real World Dependency Injection
59. <?php
class 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 III
Real World Dependency Injection
60. One class, multiple configurations III
<?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
63. Mocking external service access
Booking serviceBooking service WS-
Connector
WS-
Connector
Real World Dependency Injection
64. Mocking external service access
Booking serviceBooking service WS-
Connector
WS-
Connector WebserviceWebservice
Real World Dependency Injection
65. Mocking external service access
Booking serviceBooking service WS-
Connector
WS-
Connector WebserviceWebservice
Remember:
The contract!
Real World Dependency Injection
66. Mocking external service access
Booking serviceBooking service FS-
Connector
FS-
Connector FilesystemFilesystem
Real World Dependency Injection
67. Mocking external service access
Booking serviceBooking service FS-
Connector
FS-
Connector FilesystemFilesystem
fullfills the
contract!
Real World Dependency Injection
71. No framework dependency
<?php
class 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