8. Hardcoded Dependencies Make dependencies explicit class ProductService { ... public function __constructor() { $boostrap = Zend_Controller_Front::getInstance()->getParam('bootstrap'); $this->_cache = $boostrap->getResource('cache'); $this->_logger = $boostrap->getResource('logger'); $this->_entityManager = $boostrap->getResource('entityManager'); } } We have hardcoded dependencies when, the class set its dependencies by itself:
9.
10. New Code... Make dependencies explicit class ProductService { ... public function __constructor($cache, $logger, $entityManager) { $this->_cache = $cache; $this->_logger = $logger; $this->_entityManager = $entityManager; } } Injecting dependencies through the constructor:
11.
12. Setter Injection: The dependencies are injected trought setter, this can be good if a large numbers of dependencies are present.
15. When using dependency injection, a consumer component specifies the service contract by interface, and the injector component selects an implementation on behalf of the dependent component. (inversion of control)
16. In its simplest implementation, code that creates a dependent object supplies dependencies to that object via constructor arguments or by setting properties on the object.
22. Since the object creation is handle by a centralized component, we avoid copy paste the same code inside of different objects.
23. Dependency Injection Container DI container The Container knows: - How the create new objects. - Classes Dependencies. Cache Logger EManager ProductService Cache Logger Event Manager An object and its dependencies can be created and initialized by a ”Dependency - Injection Container”.
26. Butterfly Java example using anotations: @Component public class SomeClass { @Autowired(required=true) public SomeClass(OtherClass bean1, OtherClass bean2) { ... } }
27.
28. Written by Fabien Potencier, stand alone library http://components.symfony-project.org/ stable version
32. Creating the Container (Boostraping) from http://components.symfony-project.org/ require_once '/PATH/TO/sfServiceContainerAutoloader.php'; sfServiceContainerAutoloader::register(); $sc = new sfServiceContainerBuilder(); $loader = new sfServiceContainerLoaderFileXml($sc); $loader->load('/somewhere/container.xml'); $sc->ipManager From http://components.symfony-project.org/dependency-injection/trunk/book/05-Service-Description
34. Need for Speed from http://components.symfony-project.org/ ..... $phpCointernerClassCode = $dumper->dump(array('class' => 'Container')); file_put_contents('/somewhere/container.php', $code); Symfony DI compoment has a mechanism where optimized 'plain' php container classes can be Generated from configuration. Once generated those containers classes can be used avoiding parsing configuration files every time.
35. Need for Speed from http://components.symfony-project.org/ class SymfonyContainerDev extends sfServiceContainer { protected function getLogerService() { if (isset($this->shared['loger'])) return $this->shared['loger']; $instance = call_user_func(array('MyLib_Log', 'getResource')); return $this->shared['loger'] = $instance; } protected function getIpManagerService() { if (isset($this->shared['ipManager'])) return $this->shared['ipManager']; $instance = new Fishpond_Gearman_Client_Competitor_IpManager( $this->getService('documentManager'), $this->getService('gearmanClient'), $this->getService('ipmanager.logger')); return $this->shared['ipManager'] = $instance; } ...... ..... } The Container Builder use the configuration to create a php container class that is able to create an inject dependencies. The Container class created it is optimized for speed and don't have any overhead (parsing configuration files, etc).
36.
37. Note: Production and development in this example use diferent xml files, in this way we can use different definitions for diffrent enviroments.