the state of di - dpc12

Post on 13-Jan-2015

1.011 Views

Category:

Technology

0 Downloads

Preview:

Click to see full reader

DESCRIPTION

 

TRANSCRIPT

The state of DI in PHP

The state of DI in PHP

About me

Stephan Hochdörfer, bitExpert AG

Department Manager Research Labs

enjoying PHP since 1999

7 years of DI experience (in PHP)

S.Hochdoerfer@bitExpert.de

@shochdoerfer

The state of DI in PHP

What are Dependencies?

Are Dependencies bad?

The state of DI in PHP

Are Dependencies bad?

Not at all!

The state of DI in PHP

Are Dependencies bad?

Hard-coded dependencies are bad!

The state of DI in PHP

Tightly coupled code

The state of DI in PHP

No reuse of components

The state of DI in PHP

No isolation, not testable!

The state of DI in PHP

The state of DI in PHP

Dependency madness!

What`s DI about?

The state of DI in PHP

What`s DI about?

The state of DI in PHP

new TalkService(new TalkRepository());

What`s DI about?

Consumer

The state of DI in PHP

What`s DI about?

Consumer Dependencies

The state of DI in PHP

What`s DI about?

Consumer Dependencies Container

The state of DI in PHP

What`s DI about?

Consumer Dependencies Container

The state of DI in PHP

A little bit of history...

The state of DI in PHP

1988

The state of DI in PHP

„Designing Reusable Classes“Ralph E. Johnson & Brian Foote

1996

The state of DI in PHP

„The Dependency Inversion Principle“Robert C. Martin

2004

The state of DI in PHP

„Inversion of Control Containers and the Dependency Injection pattern“

Martin Fowler

2005 / 2006

The state of DI in PHP

Garden, a lightweight DI container for PHP.

2006

The state of DI in PHP

First PHP5 framework with DI support

2007

The state of DI in PHP

International PHP Conference 2007 features 2 talks about DI.

2011

The state of DI in PHP

Zend Framework 2 (beta),Symfony2, Flow3, ...

Choose wisely!

Simple Container vs. Full stacked DI Framework

The state of DI in PHP

The state of DI in PHP

Pimple

Pimple – First steps

The state of DI in PHP

<?php

class TalkService {public function __construct() {}

public function getTalks() {}

}

Pimple – First steps

The state of DI in PHP

<?phprequire_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'];

Pimple – Constructor Injection

The state of DI in PHP

<?php

interface GenericRepository {public function readTalks();

}

class TalkRepository implements GenericRepository {public function readTalks() {}

}

class TalkService {public function __construct(TalkRepository $repo) {}

public function getTalks() {}

}

Pimple – Constructor Injection

The state of DI in PHP

<?phprequire_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'];

Pimple – Setter Injection

The state of DI in PHP

<?php

class Logger {public function doLog($logMsg) {}

}

class TalkService {public function __construct(TalkRepository $repo) {}

public function setLogger(Logger $logger) {}

public function getTalks() {}

}

Pimple – Setter Injection

The state of DI in PHP

<?phprequire_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'];

Pimple – General usage

The state of DI in PHP

<?phprequire_once '/path/to/Pimple.php';require_once '/path/to/TalkService.php';

// create the Container$container = new Pimple();

// define services in container$container['loggerShared'] = $c->share(function ($c) { return new Logger();)};$container['logger'] = function ($c) { return new Logger();};

// instantiate logger from container$logger = $container['logger'];

// instantiate shared logger from container (same instance!)$logger2 = $container['loggerShared'];$logger3 = $container['loggerShared'];

The state of DI in PHP

Bucket

Bucket – Constructor Injection

The state of DI in PHP

<?php

interface GenericRepository {public function readTalks();

}

class TalkRepository implements GenericRepository {public function readTalks() {}

}

class TalkService {public function __construct(TalkRepository $repo) {}

public function getTalks() {}

}

Bucket – Constructor Injection

The state of DI in PHP

<?phprequire_once '/path/to/bucket.inc.php';require_once '/path/to/TalkService.php';

// create the Container$container = new bucket_Container();

// instantiate talkService from container$talkService = $container->create('TalkService');

// instantiate shared instances from container$talkService2 = $container->get('TalkService');$talkService3 = $container->get('TalkService');

The state of DI in PHP

Zend\Di – First steps

The state of DI in PHP

<?phpnamespace Acme;

class TalkService {public function __construct() {}

public function getTalks() {}

}

Zend\Di – First steps

The state of DI in PHP

<?php

$di = new \Zend\Di\Di();

$service = $di->get('Acme\TalkService');$service->getTalks();

Zend\Di – Constructor Injection

The state of DI in PHP

<?phpnamespace Acme;

interface GenericRepository {public function readTalks();

}

class TalkRepository implements GenericRepository {public function readTalks() {}

}

class TalkService {public function __construct(TalkRepository $repo) {}

public function getTalks() {}

}

Zend\Di – Constructor Injection

The state of DI in PHP

<?php

$di = new \Zend\Di\Di();

$service = $di->get('Acme\TalkService');$service->getTalks();

Zend\Di – Setter Injection

The state of DI in PHP

<?phpnamespace Acme;

class Logger {public function doLog($logMsg) {}

}

class TalkService {public function __construct(TalkRepository $repo) {}

public function setLogger(Logger $logger) {}

public function getTalks() {}

}

Zend\Di – Setter Injection

The state of DI in PHP

<?php$di = new \Zend\Di\Di();$di->configure(

new Zend\Di\Configuration(array(

'definition' => array('class' => array(

'Acme\TalkService' => array('setLogger' => array('required' => true)

))

))

));

$service = $di->get('Acme\TalkService');var_dump($service);

Zend\Di – Interface Injection

The state of DI in PHP

<?phpnamespace 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() {}

}

Zend\Di – Interface Injection

The state of DI in PHP

<?php

$di = new \Zend\Di\Di();

$service = $di->get('Acme\TalkService');$service->getTalks();

Zend\Di – General usage

The state of DI in PHP

<?php

$di = new \Zend\Di\Di();

$service = $di->get('Acme\TalkService');var_dump($service);

$service2 = $di->get('Acme\TalkService');var_dump($service2); // same instance as $service

$service3 = $di->get('Acme\TalkService',array(

'repo' => new \phpbnl12\TalkRepository())

);var_dump($service3); // new instance

Zend\Di – Builder Definition

The state of DI in PHP

<?php// describe dependency$dep = new \Zend\Di\Definition\Builder\PhpClass();$dep->setName('Acme\TalkRepository');

// describe class$class = new \Zend\Di\Definition\Builder\PhpClass();$class->setName('Acme\TalkService');

// add injection method$im = new \Zend\Di\Definition\Builder\InjectionMethod();$im->setName('__construct');$im->addParameter('repo', 'Acme\TalkRepository');$class->addInjectionMethod($im);

// configure builder$builder = new \Zend\Di\Definition\BuilderDefinition();$builder->addClass($dep);$builder->addClass($class);

Zend\Di – Builder Definition

The state of DI in PHP

<?php

// add to Di$defList = new \Zend\Di\DefinitionList($builder);$di = new \Zend\Di\Di($defList);

$service = $di->get('Acme\TalkService');var_dump($service);

The state of DI in PHP

Symfony2

The state of DI in PHP

<?phpnamespace Acme\TalkBundle\Controller;use Symfony\Bundle\FrameworkBundle\Controller\Controller;use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;

class TalkController extends Controller { /** * @Route("/", name="_talk") * @Template() */ public function indexAction() { $service = $this->get('acme.talk.service'); return array(); }}

Symfony2 – Configuration file

The state of DI in PHP

<?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/serviceshttp://symfony.com/schema/dic/services/services-1.0.xsd">

</container>

File services.xml in src/Acme/DemoBundle/Resources/config

Symfony2 – Constructor Injection

The state of DI in PHP

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

<services><service id="acme.talk.repo"

class="Acme\TalkBundle\Service\TalkRepository" />

<service id="acme.talk.service" class="Acme\TalkBundle\Service\TalkService">

<argument type="service" id="acme.talk.repo" /></service>

</services></container>

Symfony2 – Setter Injection

The state of DI in PHP

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

<services><service id="acme.talk.logger"

class="Acme\TalkBundle\Service\Logger" />

<service id="acme.talk.repo" class="Acme\TalkBundle\Service\TalkRepository" />

<service id="acme.talk.service" class="Acme\TalkBundle\Service\TalkService">

<argument type="service" id="acme.talk.repo" /><call method="setLogger">

<argument type="service" id="acme.talk.logger" /></call>

</service></services>

</container>

Symfony2 – Setter Injection (optional)

The state of DI in PHP

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

<services><service id="acme.talk.logger"

class="Acme\TalkBundle\Service\Logger" />

<service id="acme.talk.repo" class="Acme\TalkBundle\Service\TalkRepository" />

<service id="acme.talk.service" class="Acme\TalkBundle\Service\TalkService">

<argument type="service" id="acme.talk.repo" /><call method="setLogger">

<argument type="service" id="acme.talk.logger" on-invalid="ignore" />

</call></service>

</services></container>

Symfony2 – Property Injection

The state of DI in PHP

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

<services><service id="acme.talk.repo"

class="Acme\TalkBundle\Service\TalkRepository" />

<service id="acme.talk.service" class="Acme\TalkBundle\Service\TalkService">

<property name="talkRepository" type="service" id="acme.talk.repo" />

</service></services>

</container>

Symfony2 – Interface Injection

The state of DI in PHP

Not supported!

Symfony2 – private/public Services

The state of DI in PHP

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

<services><service id="acme.talk.logger"

class="Acme\TalkBundle\Service\Logger" public="false" />

<service id="acme.talk.repo" class="Acme\TalkBundle\Service\TalkRepository" />

<service id="acme.talk.service" class="Acme\TalkBundle\Service\TalkService">

<argument type="service" id="acme.talk.repo" /><call method="setLogger">

<argument type="service" id="acme.talk.logger" /></call>

</service></services>

</container>

Symfony2 – Service inheritance

The state of DI in PHP

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

<services><service id="acme.talk.serviceparent"

class="Acme\TalkBundle\Service\TalkService" abstract="true"><property name="talkRepository" type="service"

id="acme.talk.repo" /></service>

<service id="acme.talk.service" parent="acme.talk.serviceparent" />

<service id="acme.talk.service2" parent="acme.talk.serviceparent" /></services>

</container>

Symfony2 – Service scoping

The state of DI in PHP

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

<services><service id="acme.talk.repo"

class="Acme\TalkBundle\Service\TalkRepository" />

<service id="acme.talk.service"class="Acme\TalkBundle\Service\TalkService" scope="prototype"><property name="talkRepository" type="service"

id="acme.talk.repo" /></service>

</services></container>

The state of DI in PHP

Flow3 – Constructor Injection

The state of DI in PHP

<?phpnamespace Acme\Demo\Controller;

use TYPO3\FLOW3\Annotations as FLOW3;

/** * @FLOW3\Scope("session") */class StandardController extends \TYPO3\FLOW3\MVC\Controller\ActionController {

/** * @var \Acme\Demo\Service\TalkServiceInterface */protected $talkService;

public function __construct(\Acme\Demo\Service\TalkService $talkService) {$this->talkService = $talkService;

}

public function indexAction() {}

}

Flow3 – Setter Injection (manually)

The state of DI in PHP

<?phpnamespace Acme\Demo\Controller;

use TYPO3\FLOW3\Annotations as FLOW3;

/** * @FLOW3\Scope("session") */class StandardController extends \TYPO3\FLOW3\MVC\Controller\ActionController {

/** * @var \Acme\Demo\Service\TalkServiceInterface */protected $talkService;

public function setTalkService(\Acme\Demo\Service\TalkService $talkService) {$this->talkService = $talkService;

}

public function indexAction() {}

}

Flow3 – Setter Injection (manually)

The state of DI in PHP

File Objects.yaml in Packages/Application/Acme.Demo/Configuration# @package AcmeAcme\Demo\Controller\StandardController: properties: talkService: object: Acme\Demo\Service\TalkService

Flow3 – Setter Injection (Automagic)

The state of DI in PHP

<?phpnamespace Acme\Demo\Controller;

use TYPO3\FLOW3\Annotations as FLOW3;

/** * @FLOW3\Scope("session") */class StandardController extends \TYPO3\FLOW3\MVC\Controller\ActionController {

/** * @var \Acme\Demo\Service\TalkServiceInterface */protected $talkService;

public function injectTalkService(\Acme\Demo\Service\TalkService $talkService) {$this->talkService = $talkService;

}

public function indexAction() {}

}

Flow3 – Setter Injection (Automagic)

The state of DI in PHP

<?phpnamespace Acme\Demo\Controller;

use TYPO3\FLOW3\Annotations as FLOW3;

/** * @FLOW3\Scope("session") */class StandardController extends \TYPO3\FLOW3\MVC\Controller\ActionController {

/** * @var \Acme\Demo\Service\TalkServiceInterface */protected $talkService;

public function injectSomethingElse(\Acme\Demo\Service\TalkService $talkService) {$this->talkService = $talkService;

}

public function indexAction() {}

}

Flow3 – Property Injection

The state of DI in PHP

<?phpnamespace Acme\Demo\Controller;

use TYPO3\FLOW3\Annotations as FLOW3;

/** * @FLOW3\Scope("session") */class StandardController extends \TYPO3\FLOW3\MVC\Controller\ActionController {

/** * @var \Acme\Demo\Service\TalkService * @FLOW3\Inject */protected $talkService;

public function indexAction() {}

}

Flow3 – Property Injection (with Interface)

The state of DI in PHP

<?phpnamespace Acme\Demo\Controller;

use TYPO3\FLOW3\Annotations as FLOW3;

/** * @FLOW3\Scope("session") */class StandardController extends \TYPO3\FLOW3\MVC\Controller\ActionController {

/** * @var \Acme\Demo\Service\TalkServiceInterface * @FLOW3\Inject */protected $talkService;

public function indexAction() {}

}

Flow3 – Property Injection (with Interface)

The state of DI in PHP

# @package AcmeAcme\Demo\Service\TalkServiceInterface: className: 'Acme\Demo\Service\TalkService'

File Objects.yaml in Packages/Application/Acme.Demo/Configuration

Flow3 – Scoping

The state of DI in PHP

<?phpnamespace Acme\Demo\Controller;

use TYPO3\FLOW3\Annotations as FLOW3;

/** * @FLOW3\Scope("session") */class StandardController extends \TYPO3\FLOW3\MVC\Controller\ActionController {

/** * @var \Acme\Demo\Service\TalkServiceInterface * @FLOW3\Inject */protected $talkService;

public function indexAction() {}

}

Benefits

Real World Dependency Injection

Benefits

Loose coupling, reuse of components!

Real World Dependency Injection

Benefits

Can reduce the amount of code!

Real World Dependency Injection

Benefits

Helps developers to understand the code!

Real World Dependency Injection

Cons – Developers need mindshift

Configuration ↔ Runtime

Real World Dependency Injection

The state of DI in PHP

Cons - PSR for DI container missing!

The state of DI in PHP

Lack of IDE support

Thank you!

http://joind.in/6250

top related