dependency injection, zend framework and symfony container
TRANSCRIPT
Dependency Injection
Integration of Symfony DI Container to
Zend Framework
Who am I ?
Diego Lewin
Software Architect at www.fishpond.co.nz Technical Director at www.reddelacosta.com.arConsultant at www.bookfinda.com.au
What is a dependency ?
What is a dependency
Product Service class
Cache class
Loging class
EntityManager class
'Object A' dependends on 'Object B' if 'Object A' needs 'Object B' in order to execute correctly.(Jakob Jenkov)
More dependencies
Chaining dependencies
Product Service class
Cache class
Loging class
EntityManager class
DB Writer class
Frontend class
Backend class
Log Writer class
As the size of the applications grows, the amount and complexity of dependencies grows as well
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:
Dependency Injection ?
Make dependencies explicit
Inject the dependencies classes from outside through the constructor or setter methods, instead of retrived by the object itself.
.....
$cache = $boostrap->getResource('cache')$logger = $boostrap->getResource('logger')$entityManager = $boostrap->getResource('entityManager')
$productService = new ProductService($cache, $logger, $entityManager);
Injecting dependencies through the constructor:
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:
Dependency InjectionTypes
Constructor Injection: The dependencies are injected trought the constructor. Advantage is that always when created the object is ready to be used.
Setter Injection: The dependencies are injected trought setter, this can be good if a large numbers of dependencies are present.
Interface: Components implement specific containers provided by the containers in order to be configured.
Dependency Injection
Without dependency injection, a consumer component that needs a particular service in order to accomplish a task must create an instance of a class that concretely implements the dependency interface.
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)
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.
Wikipedia (http://en.wikipedia.org/wiki/Dependency_injection)
Advantages
Make dependencies explicit: Makes it clear which are the dependencies, we don't have to go trought all the code to see which are the dependencies.
Loose Coupling.
More Testable code: Unit test, able to replace for Mocks objects.
Inject different object for different environments (different logger for dev/production).
Since the object creation is handle by a centralized component, we avoid copy paste the same code inside of different objects.
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.
DI Containers in Java
Spring
Pico
Butterfly
Java example using anotations:
@Componentpublic class SomeClass { @Autowired(required=true) public SomeClass(OtherClass bean1, OtherClass bean2) { ... }}
PHP and DI containers
Symfony Dependency Injection Written by Fabien Potencier, stand alone library http://components.symfony-project.org/ stable version
Zend Framework 2 DI Component (Beta 1)Not ready yet, but promising.
Symfony Dependency Injection
Available Formats:
- PHP
- XML
- YAML
- INI (only be able to define paramenters, no services)
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
Service Definition (XML format)
from http://components.symfony-project.org/
php://output %ipmanager.loger.file%
........
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 classescan be Generated from configuration.
Once generated those containers classes can be used avoiding parsing configuration files every time.
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).
Symfony DI - ZF Integration
Custom_Resource_Symfonycontainer
I worte a 'Custom Zend Application Resource' ,to define diferent services we use the container configuration files described in the documentation, and we use the 'application.ini' only to configure the resource itself.
You can find the code at: https://github.com/diegol/Sympony-Dependency-Injection-Zend-Framwerok-Resource ):
application.ini:
[production]resources.symfonycontainer.libraryPath = LIBRARY_PATH "/Symfony/DependencyInjection/"
resources.symfonycontainer.configContainerFile = APPLICATION_PATH "/configs/services/sfServices-production.xml"
resources.symfonycontainer.dumpFile = APPLICATION_PATH "/Containers/SymfonyContainerDev.php"
resources.symfonycontainer.containerClass = "SymfonyContainerDev"
resources.symfonycontainer.generateContainerClasses = false
[development]resources.symfonycontainer.configContainerFile = APPLICATION_PATH "/configs/services/sfServices-development.xml"resources.symfonycontainer.generateContainerClasses = true
Note: Production and development in this example use diferent xml files, in this way we can use different definitions for diffrent enviroments.
Symfony DI - ZF Integration
To use it (not as tidy as Java):
$productService = $boostrap->getResource('symfonycontainer') ->getContainerBuilder() ->productService;
(byYak_Shaving)
Questions ?
Thanks..
You can find the code at: https://github.com/diegol/Sympony-Dependency-Injection-Zend-Framwerok-Resource
Muokkaa otsikon tekstimuotoa napsauttamalla
Muokkaa jsennyksen tekstimuotoa napsauttamallaToinen jsennystasoKolmas jsennystasoNeljs jsennystasoViides jsennystasoKuudes jsennystasoSeitsems jsennystasoKahdeksas jsennystasoYhdekss jsennystaso