Introduction to DI(C)

2,087 views

Published on

Quick introduction to Dependency Injection (Container).

Published in: Technology, Business
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
2,087
On SlideShare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
14
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Introduction to DI(C)

  1. 1. Introduction to DI(C)meet.php #5 http://meetphp.pl/ 19.05.2012
  2. 2. About me$speaker = new Speaker;$speaker->name = "Radosław Benkel";$speaker->twitter = "@singlespl";$speaker->blog = "http://blog.rbenkel.me";$speaker->givePresentation();
  3. 3. What?
  4. 4. What?DependencyInjectionContainer
  5. 5. What?Dependency
  6. 6. Dependencyclass TwitterAPIClient{ protected $httpClient; public function __construct() { $this->httpClient = new SomeCurlWrapper(); } /* ... */}$client = new TwitterApiClient;
  7. 7. Dependency This
  8. 8.  is
  9. 9.  your
  10. 10.  dependency.class TwitterAPIClient{ protected $httpClient; public function __construct() { $this-httpClient = new SomeCurlWrapper(); } /* ... */}$client = new TwitterApiClient;
  11. 11. Dependency“What’s
  12. 12.  wrong
  13. 13.  with
  14. 14.   that”?
  15. 15. DependencyTry testing it...
  16. 16. Dependency...or change client implementation
  17. 17. Dependency
  18. 18. DependencySo let’s use Injection
  19. 19. What?Injection
  20. 20. Injectionclass TwitterAPIClient{ protected $httpClient; public function __construct($httpClient) { $this-httpClient = $httpClient; } /* ... */} And
  21. 21.  here
  22. 22.  you
  23. 23.  inject
  24. 24.  dependency$client = new TwitterApiClient(new SomeCurlWrapper);
  25. 25. Injection So...
  26. 26. Injectionpublic function __construct(){ $this-httpClient = new SomeCurlWrapper();} VSpublic function __construct($httpClient){ $this-httpClient = $httpClient;}
  27. 27. Injectionit’s just like...
  28. 28. Injection VS
  29. 29. Injection VSTry
  30. 30.  replacing
  31. 31.  battery,
  32. 32.  and
  33. 33.  you
  34. 34.  will
  35. 35.  now
  36. 36.  what
  37. 37.  I’m
  38. 38.  talking
  39. 39.   about.
  40. 40.  
  41. 41. InjectionInjection types:
  42. 42. Injection Injection types:• constructor injection
  43. 43. Injection Injection types:• constructor injection• setter injection
  44. 44. Injection Injection types:• constructor injection• setter injection• interface injection
  45. 45. Injection Constructor injectionclass TwitterAPIClient{ protected $httpClient; public function __construct($httpClient) { $this-httpClient = $httpClient; } /* ... */}$client = new TwitterApiClient(new SomeCurlWrapper);
  46. 46. Injection Setter injectionclass TwitterAPIClient{ protected $httpClient; public function __construct() {} public function setHttpClient($httpClient) { $this-httpClient = $httpClient; } /* ... */}$client = new TwitterApiClient;$client-setHttpClient(new SomeCurlWrapper);
  47. 47. Injection Interface injectioninterface 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);
  48. 48. InjectionSo far so good...
  49. 49. Injection...until you don’t have to do something like that:
  50. 50. 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));
  51. 51. Injection
  52. 52. Injection“How
  53. 53.  to
  54. 54.  solve
  55. 55.  that”?
  56. 56. InjectionJust use...
  57. 57. What?Container
  58. 58. Containerrequire_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));
  59. 59. Containerrequire_once container_dev.php;$mapper = $container-get(mapper.user);/* mapper is UserMapperDB, with different PDO configuration.*/$mapper-save(new User(John, Doe));
  60. 60. Containerrequire_once container_prod.php;$mapper = $container-get(mapper.user);$mapper-save(new User(John, Doe)); Find
  61. 61.  the
  62. 62.  differencerequire_once container_dev.php;$mapper = $container-get(mapper.user);$mapper-save(new User(John, Doe));
  63. 63. Containerrequire_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));
  64. 64. Containerrequire_once container_prod.php;$mapper = $container-get(mapper.user);$mapper-save(new User(John, Doe)); Find
  65. 65.  the
  66. 66.  difference Configures
  67. 67.  services
  68. 68.  in
  69. 69.  different
  70. 70.  way,
  71. 71.  but
  72. 72.   for
  73. 73.  you,
  74. 74.  API
  75. 75.  for
  76. 76.  mapper
  77. 77.  is
  78. 78.  the
  79. 79.  same.require_once container_dev.php;$mapper = $container-get(mapper.user);$mapper-save(new User(John, Doe));
  80. 80. Containerrequire_once container_prod.php;$mapper = $container-get(mapper.user);$mapper-save(new User(John, Doe)); *
  81. 81.  Assuming,
  82. 82.  tthe
  83. 83.  difference the
  84. 84.   Find
  85. 85.   hat
  86. 86.  all
  87. 87.  mappers
  88. 88.  share
  89. 89.  same
  90. 90.  interface,
  91. 91.  which
  92. 92.  they
  93. 93.  rather
  94. 94.  should.require_once container_dev.php;$mapper = $container-get(mapper.user);$mapper-save(new User(John, Doe));
  95. 95. ContainerSo, DIC it’s something like:
  96. 96. Container
  97. 97. Container What it does:• injects object dependencies• creates objects on demand• objects could be shared• (and sometimes other stuff, like tagging, XML/ JSON/YAML config etc. )
  98. 98. ContainerSo. Lets write simple one.
  99. 99. Containerclass 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; } }}
  100. 100. Containerclass Container{ protected $items = array(); *
  101. 101.  Inspired
  102. 102.  by
  103. 103.  Pimple 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; } }}
  104. 104. InjectionLets use that.
  105. 105. InjectionReplacing this:
  106. 106. 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));
  107. 107. Injectionwith this:
  108. 108. Injectionrequire_once container_prod.php;$mapper = $container-get(mapper.user);/* mapper is UserMapperEncrypted, which uses UserMapperCached(using Redis for cache), which uses UserMapperDB, which usesPDO. */$mapper-save(new User(John, Doe));
  109. 109. InjectionBecause everything is configured in container...
  110. 110. 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) );});
  111. 111. Injection...you can change e.g cache adapter...
  112. 112. 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) );});
  113. 113. 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) );});
  114. 114. Injection...and your your codehasn’t changed at all.
  115. 115. Injectionrequire_once container_prod.php;$mapper = $container-get(mapper.user);/* mapper is UserMapperEncrypted, which uses UserMapperCached(using Apc for cache), which uses UserMapperDB, which usesPDO. */$mapper-save(new User(John, Doe));
  116. 116. Container But probably, youshould use another DIC:
  117. 117. Container• AuraDI http://auraphp.github.com/Aura.Di/• Pimple http://pimple.sensiolabs.org/• Symfony 2 Dependency Injection Component http://symfony.com/doc/current/components/dependency_injection/ introduction.html• ZF2 Dependency Injection http://framework.zend.com/wiki/display/ZFDEV2/Zend+DI+QuickStart• Twittee http://twittee.org/
  118. 118. Container• AuraDI PHP
  119. 119.  5.4
  120. 120.  only http://auraphp.github.com/Aura.Di/• Pimple http://pimple.sensiolabs.org/• Symfony 2 Dependency Injection Component http://symfony.com/doc/current/components/dependency_injection/ introduction.html• ZF2 Dependency Injection http://framework.zend.com/wiki/display/ZFDEV2/Zend+DI+QuickStart• Twittee http://twittee.org/
  121. 121. Container• AuraDI http://auraphp.github.com/Aura.Di/• Pimple Small,
  122. 122.  basic http://pimple.sensiolabs.org/• Symfony 2 Dependency Injection Component http://symfony.com/doc/current/components/dependency_injection/ introduction.html• ZF2 Dependency Injection http://framework.zend.com/wiki/display/ZFDEV2/Zend+DI+QuickStart• Twittee http://twittee.org/
  123. 123. Container• AuraDI Lot’s
  124. 124.  of
  125. 125.  features http://auraphp.github.com/Aura.Di/• Pimple http://pimple.sensiolabs.org/• Symfony 2 Dependency Injection Component http://symfony.com/doc/current/components/dependency_injection/ introduction.html• ZF2 Dependency Injection http://framework.zend.com/wiki/display/ZFDEV2/Zend+DI+QuickStart• Twittee http://twittee.org/
  126. 126. Container• AuraDI http://auraphp.github.com/Aura.Di/• Pimple http://pimple.sensiolabs.org/• Symfony 2 Dependency Injection Component http://symfony.com/doc/current/components/dependency_injection/ introduction.html• ZF2 Dependency Injection http://framework.zend.com/wiki/display/ZFDEV2/Zend+DI+QuickStart• Twittee http://twittee.org/ Fits
  127. 127.  into
  128. 128.  tweet!
  129. 129. Thank you!

×