Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Introduction to DI(C)

Introduction to DI(C)

Quick introduction to Dependency Injection (Container).

3a453374a79becf33b3a6659389a56c4?s=128

Radek Benkel

May 21, 2012
Tweet

Transcript

  1. Introduction to DI(C) meet.php # . . http://meetphp.pl/

  2. $speaker = new Speaker; $speaker->name = "Radosław Benkel"; $speaker->twitter =

    "@singlespl"; $speaker->blog = "http://blog.rbenkel.me"; $speaker->givePresentation(); About me
  3. What?

  4. Dependency Injection Container What?

  5. Dependency What?

  6. Dependency class TwitterAPIClient { protected $httpClient; public function __construct() {

    $this->httpClient = new SomeCurlWrapper(); } /* ... */ } $client = new TwitterApiClient;
  7. Dependency class TwitterAPIClient { protected $httpClient; public function __construct() {

    $this->httpClient = new SomeCurlWrapper(); } /* ... */ } $client = new TwitterApiClient; This
  8. “What’s

  9. Try testing it... Dependency

  10. ...or change client implementation Dependency

  11. Dependency

  12. So let’s use Injection Dependency

  13. Injection What?

  14. Injection class TwitterAPIClient { protected $httpClient; public function __construct($httpClient) {

    $this->httpClient = $httpClient; } /* ... */ } $client = new TwitterApiClient(new SomeCurlWrapper); And
  15. So... Injection

  16. Injection public function __construct() { $this->httpClient = new SomeCurlWrapper(); }

    public function __construct($httpClient) { $this->httpClient = $httpClient; } VS
  17. it’s just like... Injection

  18. Injection VS

  19. Injection VS Try

  20. Injection types: Injection

  21. Injection types: Injection • constructor injection

  22. Injection types: Injection • constructor injection • setter injection

  23. Injection types: Injection • constructor injection • setter injection •

    interface injection
  24. Constructor injection Injection class TwitterAPIClient { protected $httpClient; public function

    __construct($httpClient) { $this->httpClient = $httpClient; } /* ... */ } $client = new TwitterApiClient(new SomeCurlWrapper);
  25. Setter injection Injection class TwitterAPIClient { protected $httpClient; public function

    __construct() {} public function setHttpClient($httpClient) { $this->httpClient = $httpClient; } /* ... */ } $client = new TwitterApiClient; $client->setHttpClient(new SomeCurlWrapper);
  26. Interface injection Injection interface HttpClientInterface { public function setHttpClient($httpClient); }

    class TwitterAPIClient implements HttpClientInterface { protected $httpClient; public function __construct() {} public function setHttpClient($httpClient) { $this->httpClient = $httpClient; } /* ... */ } $client = new TwitterApiClient; $client->setHttpClient(new SomeCurlWrapper);
  27. So far so good... Injection

  28. ...until you don’t have to do something like that: Injection

  29. Injection $mapper = new UserMapperEncrypted( new UserMapperCached( new UserMapperDB( new

    PDO( 'mysql:host=127.0.0.1', 'user', 'password' ) ), new RedisCacheAdapter( '127.0.0.1:6379' ) ), 'YourSuperSecretPass' ); $mapper->save(new User('John', 'Doe'));
  30. Injection

  31. Injection “How

  32. Just use... Injection

  33. Container What?

  34. Container require_once "container_prod.php"; $mapper = $container->get('mapper.user'); /* mapper is UserMapperEncrypted,

    which uses UserMapperCached, which uses UserMapperDB, which uses PDO. */ $mapper->save(new User('John', 'Doe'));
  35. Container require_once "container_dev.php"; $mapper = $container->get('mapper.user'); /* mapper is UserMapperDB,

    with different PDO configuration. */ $mapper->save(new User('John', 'Doe'));
  36. Container require_once "container_prod.php"; $mapper = $container->get('mapper.user'); $mapper->save(new User('John', 'Doe')); require_once

    "container_dev.php"; $mapper = $container->get('mapper.user'); $mapper->save(new User('John', 'Doe')); Find
  37. Container require_once "container_prod.php"; $mapper = $container->get('mapper.user'); $mapper->save(new User('John', 'Doe')); require_once

    "container_dev.php"; $mapper = $container->get('mapper.user'); $mapper->save(new User('John', 'Doe'));
  38. Container require_once "container_prod.php"; $mapper = $container->get('mapper.user'); $mapper->save(new User('John', 'Doe')); require_once

    "container_dev.php"; $mapper = $container->get('mapper.user'); $mapper->save(new User('John', 'Doe')); Find
  39. Container require_once "container_prod.php"; $mapper = $container->get('mapper.user'); $mapper->save(new User('John', 'Doe')); require_once

    "container_dev.php"; $mapper = $container->get('mapper.user'); $mapper->save(new User('John', 'Doe')); Find
  40. So, DIC it’s something like: Container

  41. Container

  42. What it does: Container • injects object dependencies • creates

    objects on demand • objects could be shared • (and sometimes other stuff, like tagging, XML/ JSON/YAML config etc. )
  43. So. Lets write simple one. Container

  44. Container class Container { protected $items = array(); public function

    get($key) { $item = $this->items[$key]; return is_callable($item) ? $item($this) : $item; } public function set($key, $value, $shared = false) { if ($shared === true && is_callable($value)) { $this->items[$key] = function($c) use ($value) { static $obj; if (!$obj) { $obj = $value($c); } return $obj; }; } else { $this->items[$key] = $value; } } }
  45. Container class Container { protected $items = array(); public function

    get($key) { $item = $this->items[$key]; return is_callable($item) ? $item($this) : $item; } public function set($key, $value, $shared = false) { if ($shared === true && is_callable($value)) { $this->items[$key] = function($c) use ($value) { static $obj; if (!$obj) { $obj = $value($c); } return $obj; }; } else { $this->items[$key] = $value; } } } *
  46. Lets use that. Injection

  47. Replacing this: Injection

  48. Injection $mapper = new UserMapperEncrypted( new UserMapperCached( new UserMapperDB( new

    PDO( 'mysql:host=127.0.0.1', 'user', 'password' ) ), new RedisCacheAdapter( '127.0.0.1:6379' ) ), 'YourSuperSecretPass' ); $mapper->save(new User('John', 'Doe'));
  49. with this: Injection

  50. Injection require_once "container_prod.php"; $mapper = $container->get('mapper.user'); /* mapper is UserMapperEncrypted,

    which uses UserMapperCached (using Redis for cache), which uses UserMapperDB, which uses PDO. */ $mapper->save(new User('John', 'Doe'));
  51. Because everything is configured in container... Injection

  52. Injection //container_prod.php $c = new Container(); $c->set('pdo.dsn', 'mysql:host=127.0.0.1'); $c->set('pdo.user', 'user');

    $c->set('pdo.pass', 'password'); $c->set('redis.host', '127.0.0.1:6379'); $c->set('mcrypt.key', 'YourSuperSecretPass'); $c->set('pdo', function(Container $c) { return new PDO( $c->get('pdo.dsn'), $c->get('pdo.user'), $c->get('pdo.pass'), ); }, true); $c->set('cache.adapter', function(Container $c) { return new RedisCacheAdapter($c->get('redis.host')); }); $c->set('mapper.user', function(Container $c) { return new UserMapperEncrypted( new UserMapperCached( new UserMapperDB($c->get('pdo')), $c->get('cache.adapter') ), $c->get('mcrypt.key') ); });
  53. ...you can change e.g cache adapter... Injection

  54. Injection //container_prod.php $c = new Container(); $c->set('pdo.dsn', 'mysql:host=127.0.0.1'); $c->set('pdo.user', 'user');

    $c->set('pdo.pass', 'password'); $c->set('mcrypt.key', 'YourSuperSecretPass'); $c->set('pdo', function(Container $c) { return new PDO( $c->get('pdo.dsn'), $c->get('pdo.user'), $c->get('pdo.pass'), ); }, true); $c->set('cache.adapter', function(Container $c) { return new ApcCacheAdapter(); }); $c->set('mapper.user', function(Container $c) { return new UserMapperEncrypted( new UserMapperCached( new UserMapperDB($c->get('pdo')), $c->get('cache.adapter') ), $c->get('mcrypt.key') ); });
  55. Injection //container_prod.php $c = new Container(); $c->set('pdo.dsn', 'mysql:host=127.0.0.1'); $c->set('pdo.user', 'user');

    $c->set('pdo.pass', 'password'); $c->set('mcrypt.key', 'YourSuperSecretPass'); $c->set('pdo', function(Container $c) { return new PDO( $c->get('pdo.dsn'), $c->get('pdo.user'), $c->get('pdo.pass'), ); }, true); $c->set('cache.adapter', function(Container $c) { return new ApcCacheAdapter(); }); $c->set('mapper.user', function(Container $c) { return new UserMapperEncrypted( new UserMapperCached( new UserMapperDB($c->get('pdo')), $c->get('cache.adapter') ), $c->get('mcrypt.key') ); });
  56. ...and your your code hasn’t changed at all. Injection

  57. Injection require_once "container_prod.php"; $mapper = $container->get('mapper.user'); /* mapper is UserMapperEncrypted,

    which uses UserMapperCached (using Apc for cache), which uses UserMapperDB, which uses PDO. */ $mapper->save(new User('John', 'Doe'));
  58. But probably, you should use another DIC: Container

  59. • AuraDI http://auraphp.github.com/Aura.Di/ • Pimple http://pimple.sensiolabs.org/ • Symfony Dependency Injection

    Component http://symfony.com/doc/current/components/dependency_injection/ introduction.html • ZF Dependency Injection http://framework.zend.com/wiki/display/ZFDEV /Zend+DI+QuickStart • Twittee http://twittee.org/ Container
  60. • AuraDI http://auraphp.github.com/Aura.Di/ • Pimple http://pimple.sensiolabs.org/ • Symfony Dependency Injection

    Component http://symfony.com/doc/current/components/dependency_injection/ introduction.html • ZF Dependency Injection http://framework.zend.com/wiki/display/ZFDEV /Zend+DI+QuickStart • Twittee http://twittee.org/ Container PHP
  61. • AuraDI http://auraphp.github.com/Aura.Di/ • Pimple http://pimple.sensiolabs.org/ • Symfony Dependency Injection

    Component http://symfony.com/doc/current/components/dependency_injection/ introduction.html • ZF Dependency Injection http://framework.zend.com/wiki/display/ZFDEV /Zend+DI+QuickStart • Twittee http://twittee.org/ Container Small,
  62. • AuraDI http://auraphp.github.com/Aura.Di/ • Pimple http://pimple.sensiolabs.org/ • Symfony Dependency Injection

    Component http://symfony.com/doc/current/components/dependency_injection/ introduction.html • ZF Dependency Injection http://framework.zend.com/wiki/display/ZFDEV /Zend+DI+QuickStart • Twittee http://twittee.org/ Container Lot’s
  63. • AuraDI http://auraphp.github.com/Aura.Di/ • Pimple http://pimple.sensiolabs.org/ • Symfony Dependency Injection

    Component http://symfony.com/doc/current/components/dependency_injection/ introduction.html • ZF Dependency Injection http://framework.zend.com/wiki/display/ZFDEV /Zend+DI+QuickStart • Twittee http://twittee.org/ Container Fits
  64. Thank you!