The Flip Side of Dependency Injection - The PHP Consulting ...
-
Upload
khangminh22 -
Category
Documents
-
view
0 -
download
0
Transcript of The Flip Side of Dependency Injection - The PHP Consulting ...
» Working with PHP for over a decade(Security paranoid ;) and System Architect)
» Author of phpab and phpDox
» Co-Founder and Consultantwith thePHP.cc
Arne Blankerts
The Problem1 <?php23 classclass Sample {45 privateprivate $backend$backend;6 privateprivate $service$service;78 public functionpublic function __construct() {9 $config$config = newnew Config('/path/to/some.ini');
10 $this$this->backend = newnew Backend($config$config);11 $this$this->service = newnew SuperService($config$config, 'Sample');12 }1314 }
Solution - Attempt 11 <?php23 classclass Sample {45 privateprivate $backend$backend;6 privateprivate $service$service;78 public functionpublic function __construct() {9 $config$config = Config::getInstance();
10 $this$this->backend = newnew Backend($config$config);11 $this$this->service = newnew SuperService($config$config), 'Sample');12 }1314 }
Solution - Attempt 21 <?php23 classclass Sample {45 privateprivate $backend$backend;6 privateprivate $service$service;78 public functionpublic function __construct(Config $config$config) {9 $this$this->backend = newnew Backend($config$config);
10 $this$this->service = newnew SuperService($config$config), 'Sample');11 }1213 }
Solution - Attempt 31 <?php23 classclass Sample {45 privateprivate $backend$backend;6 privateprivate $service$service;78 public functionpublic function __construct(Config $config$config) {9 $this$this->backend = newnew Backend(
10 $config$config->get('backend.credentials')11 );12 $this$this->service = newnew SuperService(13 $config$config->get('service.hostname')14 );15 }1617 }
Solution - Attempt 41 <?php23 classclass Sample {45 privateprivate $backend$backend;6 privateprivate $service$service;78 public functionpublic function __construct(Container $container$container) {9 $this$this->backend = $container$container->get('backend');
10 $this$this->service = $container$container->get('superservice');11 }1213 }
Dependency Injection1 <?php23 classclass Sample {45 privateprivate $backend$backend;6 privateprivate $service$service;78 public functionpublic function __construct(Backend $backend$backend, Service $service$service) {9 $this$this->backend = $backend$backend;
10 $this$this->service = $service$service;11 }1213 }
Better Dependency Injection!1 <?php23 classclass Sample {45 privateprivate $backend$backend;6 privateprivate $service$service;78 public functionpublic function __construct(9 BackendInterface $backend$backend,
10 ServiceInterface $service$service11 ) {12 $this$this->backend = $backend$backend;13 $this$this->service = $service$service;14 }1516 }
Many dependencies?1 <?php23 classclass Sample {45 privateprivate $serviceA$serviceA;6 privateprivate $serviceB$serviceB;7 privateprivate $serviceC$serviceC;8 privateprivate $serviceD$serviceD;9 privateprivate $serviceE$serviceE;
1011 public functionpublic function __construct(12 ServiceAInterface $serviceA$serviceA, ServiceBInterface $serviceB$serviceB,13 ServiceCInterface $serviceC$serviceC, ServiceDInterface $serviceD$serviceD,14 ServiceEInterface $serviceE$serviceE15 ) {16 // [...]17 }1819 }
Magic?1 <?php23 classclass Sample {45 /**6 * @var ServiceInterface7 * @Inject8 */9 privateprivate $serviceA$serviceA;
1011 }
Advanced Magic?1 <?php23 classclass Sample {45 /**6 * @var ServiceInterface7 * @Inject("service.SuperServiceA")8 */9 privateprivate $serviceA$serviceA;
1011 }
Advanced advanced Magic?1 <?php23 classclass Sample {45 /**6 * @var ServiceInterface7 * @Inject("service.SuperServiceA", Instance="ThatInstance")8 */9 privateprivate $serviceA$serviceA;
1011 }
Extenral Configuration?1 services:2 serviceA:3 classclass: ServiceAImplementor4 serviceB:5 classclass: ServiceBImplementor6 serviceC:7 classclass: ServiceCImplementor
Requirements• All Dependencies must be in code• Seperate Object creation from usage• Ability to choose actual implementation on runtime
Requirements• All Dependencies must be in code
• No hidden Dependencies• No external configuration• No framework magic based on annotations
• Seperate Object Creation from Usage• Ability to choose actual implementation on runtime
Requirements• All Dependencies must be in code• Seperate Object Creation from Usage• Ability to choose actual implementation on runtime
Requirements• All Dependencies must be in code• Seperate Object Creation from Usage• Ability to choose actual Implementation on Runtime
Requirements• All Dependencies must be in code• Seperate Object Creation from Usage• Ability to choose actual Implementation on Runtime
• Run consistent A/B-Tests• Degrade gracefully• Customized execution
1 <?php23 classclass Factory {45 privateprivate $config$config;67 public functionpublic function __construct(Config $config$config) {8 $this$this->config = $config$config;9 }
1011 /**12 * @return ServiceA13 */14 public functionpublic function getServiceA() {15 return newreturn new ServiceA($this$this->getDBConnection());16 }1718 /**19 * @return DBConnection20 */21 private functionprivate function getDBConnection() {22 return newreturn new DBConnection($this$this->config->getDSN());23 }2425 }
1 <?php23 classclass FooLocator {45 /** @var Factory */6 privateprivate $factory$factory;78 public functionpublic function __construct(Factory $factory$factory) {9 $this$this->factory = $factory$factory;
10 }1112 /**13 * @return FooInterface14 */15 public functionpublic function get($type$type) {16 switchswitch ($type$type) {17 casecase 'a': returnreturn $this$this->factory->getServiceA();18 casecase 'b': returnreturn $this$this->factory->getServiceB();19 defaultdefault: throw newthrow new RuntimeException("Type '$type' not specified");20 }21 }2223 }
talks.thePHP.cc
@thePHPcc