SlideShare una empresa de Scribd logo
1 de 127
Descargar para leer sin conexión
The IoC Hydra
Kacper Gunia @cakper
Independent Consultant & Trainer
DDD London Leader @ddd_london
CHAPTER 1: THE THEORY
THIS IS NOT YET ANOTHER
DEPENDENCY INJECTION TALK ;)
SO WE NEED SOME CLARIFICATION
IOC !== DI
–Pico Container
“Inversion of Control (IoC) is a design pattern
that addresses a component’s dependency
resolution, configuration and lifecycle. ”
–Pico Container
“It suggests that the control of those three
should not be the concern of the component
itself. Thus it is inverted back.”
–Pico Container
“Dependency Injection is where components
are given their dependencies through their
constructors, methods, or directly into fields.”
Inversion of Control
Dependency
Injection
Events
AOP
WHY DO WE IOC?
PROS
• Separation of concerns:
• dependency resolution, configuration and lifecycle
• Enforcing Single Responsibility Principle
• Easier testing
• Modular architecture, loose coupling
CONS
• Learning curve
• Code is harder do analyse/debug
• Moves complexity somewhere else (doesn’t remove)
• Need for extra tools like Containers / Dispatchers
HOW DO WE WRITE SOFTWARE
WITHOUT IOC?
EXAMPLE
interface FileEraser

{

public function erase($filename);

}
EXAMPLE
interface Logger

{

public function log($log);

}



class PrintingLogger implements Logger

{

public function log($log)

{

echo $log;

}

}
EXAMPLE
class LocalFileEraser implements FileEraser

{

public function erase($filename) {

$logger = new PrintingLogger();

$logger->log("Attempt to erase file: " . $filename);



unlink($filename);



$logger->log("File " . $filename . " was erased.”);

}

}
EXAMPLE
$eraser = new LocalFileEraser();

$eraser->erase('important-passwords.txt');
HOW CAN WE FIX IT WITH DI?
EXAMPLE WITH DI
class LocalFileEraser implements FileEraser
{

private $logger;



public function __construct(Logger $logger) {

$this->logger = $logger;

}



public function erase($path) {

$this->logger->log("Attempt to erase file: " . $path);


unlink($path);


$this->logger->log("File " . $path . " was erased.");

}

}
EXAMPLE WITH DI
$logger = new PrintingLogger();

$eraser = new LocalFileEraser($logger);



$eraser->erase('important-passwords.txt');
What (is being executed)
Known Unknown
KnownUnknown
When(isbeingexecuted)
Dependency
Injection
Stages of loosening control
(from the component point of view)
HOW CAN WE FIX IT WITH EVENTS?
EXAMPLE WITH EVENTS
class FileEvent implements Event

{

private $path;

public function __construct($path)

{

$this->path = $path;

}



public function getPath()

{

return $this->path;

}

}
EXAMPLE WITH EVENTS
class FileEraseWasInitialised extends FileEvent

{



}



class FileWasErased extends FileEvent

{



}
EXAMPLE WITH EVENTS
interface Listener

{

public function handle(Event $event);

}



interface Event

{



}
EXAMPLE WITH EVENTS
class LoggingFileEventListener implements Listener

{

private $logger;



public function __construct(Logger $logger)

{

$this->logger = $logger;

}



public function handle(Event $event)

{

if ($event instanceof FileEvent) {

$this->logger->log(get_class($event).' '.$event->getPath());

}

}

}
EXAMPLE WITH EVENTS
trait Observable

{

private $listeners = [];



public function addListener(Listener $listener)

{

$this->listeners[] = $listener;

}



public function dispatch(Event $event)

{

foreach ($this->listeners as $listener) {

$listener->handle($event);

}

}

}
EXAMPLE WITH EVENTS
class LocalFileEraser implements FileEraser

{

use Observable;



public function erase($filename)

{

$this->dispatch(new FileEraseWasInitialised($filename));



unlink($filename);



$this->dispatch(new FileWasErased($filename));

}

}
EXAMPLE WITH EVENTS
$eraser = new LocalFileEraser();

$listener = new LoggingFileEventListener(new PrintingLogger());
$eraser->addListener($listener);



$eraser->erase('important-passwords.txt');
What (is being executed)
Known Unknown
KnownUnknown
When(isbeingexecuted)
Events
Stages of loosening control
(from the component point of view)
HOW CAN WE FIX IT WITH AOP?
EXAMPLE WITH AOP USING DECORATOR
class LocalFileEraser implements FileEraser

{

public function erase($filename)

{

unlink($filename);

}

}
EXAMPLE WITH AOP USING DECORATOR
class LoggingFileEraser implements FileEraser

{

private $decorated;



private $logger;



public function __construct(FileEraser $decorated, Logger $logger)

{

$this->decorated = $decorated;

$this->logger = $logger;

}



public function erase($filename)

{

$this->logger->log('File erase was initialised' . $filename);



$this->decorated->erase($filename);



$this->logger->log('File was erased' . $filename);

}

}
EXAMPLE WITH AOP USING DECORATOR
$localFileEraser = new LocalFileEraser();

$logger = new PrintingLogger();



$eraser = new LoggingFileEraser($localFileEraser, $logger);



$eraser->erase('important-passwords.txt');
What (is being executed)
Known Unknown
KnownUnknown
When(isbeingexecuted)
AOP
Stages of loosening control
(from the component point of view)
What (is being executed)
Known Unknown
KnownUnknown
When(isbeingexecuted)
Dependency
Injection
Events
AOP
Stages of loosening control
(from the component point of view)
FRAMEWORKS & LIBRARIES
A libraries provide functionality that
you decide when to call.
Frameworks provide an architecture
for the application and
decide when to call your code.
“DON’T CALL US, WE’LL CALL YOU”
aka Hollywood Principle
Frameworks utilise IoC principles
and can be seen as one of its manifestations.
CHAPTER 2: THE PRACTICE
DEPENDENCY INJECTION
CONTAINERS
WHERE DIC CAN HELP
RESOLVING GRAPHS OF OBJECTS
$dsn = 'mysql:host=localhost;dbname=testdb;charset=utf8';

$dbUsername = 'username';

$dbPassword = 'password';

$customerRepository = new CustomerRepository(new PDO($dsn, $dbUsername, $dbPassword));



$smtpHost = 'smtp.example.org';

$smtpPort = 25;

$smtpUsername = 'username';

$smtpPassword = 'password';

$transport = new Swift_SmtpTransport($smtpHost, $smtpPort);

$transport->setUsername($smtpUsername);

$transport->setPassword($smtpPassword);

$mailer = new Swift_Mailer($transport);



$loggerName = "App";

$logger = new MonologLogger($loggerName);

$stream = "app.log";

$logger->pushHandler(new MonologHandlerStreamHandler($stream));



$controller = new RegistrationController($customerRepository, $mailer, $logger);
RESOLVING GRAPHS OF OBJECTS
use PimpleContainer;



$container = new Container();



$container['dsn'] = 'mysql:host=localhost;dbname=testdb;charset=utf8';

$container['db_username'] = 'username';

$container['dsn'] = 'password';



$container['pdo'] = function ($c) {

return new PDO($c['dsn'], $c['db_username'], $c['dsn']);

};


$container['customer_repository'] = function ($c) {

return new CustomerRepository($c['pdo']);

};
RESOLVING GRAPHS OF OBJECTS
$container['smtp_host'] = 'smtp.example.org';

$container['smtp_port'] = 25;

$container['smtp_username'] = 'username';

$container['smtp_password'] = 'password';



$container['transport'] = function ($c) {

return new Swift_SmtpTransport($c['smtp_host'], $c['smtp_port']);

};



$container->extend('transport', function ($transport, $c) {

$transport->setUsername($c['smtp_username']);

$transport->setPassword($c['smtp_password']);



return $transport;

});



$container['mailer'] = function ($c) {

return new Swift_Mailer($c['transport']);

};
RESOLVING GRAPHS OF OBJECTS
$container['logger_name'] = "App";

$container['stream_name'] = "app_" . $container['environment'] . ".log";



$container['logger'] = function ($c) {

return new MonologLogger($c['logger_name']);

};



$container->extend('transport', function ($logger, $c) {

$logger->pushHandler(
new MonologHandlerStreamHandler($c[‘stream_handler'])
);



return $logger;

});



$container['stream_handler'] = function ($c) {

return new MonologHandlerStreamHandler($c['stream_name']);

};
RESOLVING GRAPHS OF OBJECTS
$container['registration_controller'] = function ($c) {

return new RegistrationController(
$c['customer_repository'],
$c['mailer'],
$c[‘logger’]
);

};
LIFECYCLE MANAGEMENT
$container['session_storage'] = function ($c) {

return new SessionStorage('SESSION_ID');

};
LIFECYCLE MANAGEMENT
$container['session_storage'] = $container->factory(function ($c) {

return new SessionStorage('SESSION_ID');

});
WHERE DIC CAN HARM
SERVICE LOCATOR
class RegistrationController {

function resetPasswordAction() {

$mailer = Container::instance()['mailer'];

//...

}

}
SERVICE LOCATOR
• Coupled to container
• Responsible for resolving dependencies
• Dependencies are hidden
• Hard to test
• Might be ok when modernising legacy!
SETTER INJECTION
SETTER INJECTION
• Forces to be defensive as dependencies are optional
• Dependency is not locked (mutable)
• In some cases can be replaced with events
• We can avoid it by using NullObject pattern
SETTER INJECTION
class LocalFileEraser implements FileEraser

{

private $logger;



public function setLogger(Logger $logger)

{

$this->logger = $logger;

}



public function erase($filename)

{

if ($this->logger instanceof Logger) {

$this->logger->log("Attempt to erase file: " . $filename);

}



unlink($filename);



if ($this->logger instanceof Logger) {

$this->logger->log("File " . $filename . " was deleted");

}

}

}
SETTER INJECTION
class LocalFileEraser implements FileEraser

{

private $logger;



public function __construct(Logger $logger)

{

$this->logger = $logger;

}



public function erase($path)

{

$this->logger->log("Attempt to erase file: " . $path);



unlink($path);



$this->logger->log("File " . $path . " was erased.”);

}

}
SETTER INJECTION
class NullLogger implements Logger {



public function log($log)

{

// whateva...

}

}



$eraser = new LocalFileEraser(new NullLogger());

$eraser->erase('important-passwords.txt');
PARTIAL APPLICATION
DI WAY OF DOING THINGS
interface Logger

{

public function log($log);

}



class PrintingLogger implements Logger

{

public function log($log)

{

echo $log;

}

}
DI WAY OF DOING THINGS
class LocalFileEraser implements FileEraser

{

private $logger;



public function __construct(Logger $logger)

{

$this->logger = $logger;

}



public function erase($path)

{

$this->logger->log("Attempt to erase file: " . $path);



unlink($path);



$this->logger->log("File " . $path . " was deleted");

}

}
DI WAY OF DOING THINGS
$logger = new PrintingLogger();

$eraser = new LocalFileEraser($logger);



$eraser->erase('important-passwords.txt');
FUNCTIONAL WAY OF DOING THINGS
$erase = function (Logger $logger, $path)

{

$logger->log("Attempt to erase file: " . $path);

unlink($path);

$logger->log("File " . $path . " was deleted");

};
FUNCTIONAL WAY OF DOING THINGS
use ReactPartial;


$erase = function (Logger $logger, $path)

{

$logger->log("Attempt to erase file: " . $path);

unlink($path);

$logger->log("File " . $path . " was deleted");

};



$erase = Partialbind($erase, new PrintingLogger());


$erase('important-passwords.txt');
CHAPTER 3: THE SYMFONY
SYMFONY/DEPENDENCY-INJECTION
FEATURES
• Many configurations formats
• Supports Factories/Configurators/Decoration
• Extendable with Compiler Passes
• Supports lazy loading of services
PERFORMANCE
PERFORMANCE OF SYMFONY DIC
• Cached/Dumped to PHP code
• In debug mode it checks whether config is fresh
• During Compilation phase container is being optimised
LARGE NUMBER OF
CONFIGURATION FILES
SLOWS CONTAINER BUILDER
SLOW COMPILATION
• Minimise number of bundles/config files used
• Try to avoid using extras like JMSDiExtraBundle
• Can be really painful on NFS
LARGE CONTAINERS
ARE SLOW TO LOAD
AND USE A LOT OF MEMORY
LARGE CONTAINERS
• Review and remove unnecessary services/bundles etc.
• Split application into smaller ones with separate kernels
PRIVATE SERVICES
PRIVATE SERVICES
• It’s only a hint for compiler
• Minor performance gain (inlines instantiation)
• Private services can still be fetched (not recommended)
LAZY LOADING OF SERVICES
LAZY LOADING OF SERVICES
• Used when instantiation is expensive or not needed
• i.e. event listeners
• Solutions:
• Injecting container directly
• Using proxy objects
INJECTING CONTAINER DIRECTLY
• As fast as it can be
• Couples service implementation to the container
• Makes testing harder
USING PROXY OBJECTS
• Easy to use (just configuration option)
• Code and test are not affected
• Adds a bit of overhead
• especially when services are called many times
• on proxy generation
DEFINING CLASS NAMES
AS PARAMETERS
DEFINING CLASS NAMES
AS PARAMETERS
• Rare use case (since decoration is supported even less)
• Adds overhead
• Removed in Symfony 3.0
CIRCULAR REFERENCES
Security
Listener
Doctrine
CIRCULAR REFERENCE
CIRCULAR REFERENCES
• Injecting Container is just a workaround
• Using setter injection after instantiation as well
• Solving design problem is the real challenge
Doctrine
Security
Listener
TokenStorage
BROKEN CIRCULAR REFERENCE
SCOPES
MEANT TO SOLVE
“THE REQUEST PROBLEM”
SCOPE DEFINES
STATE OF THE APPLICATION
PROBLEMS WITH INJECTING
REQUEST TO SERVICES
PROBLEMS WITH INJECTING
REQUEST TO SERVICES
• Causes ScopeWideningInjectionException
• Anti-pattern - Request is a Value Object
• Which means Container was managing it’s state
• Replaced with RequestStack
App
Controller A
Sub Request
Stateful
service
Sub
Request
Master Request
Stateful
service
Master
Request
Controller B
REQUESTS MANAGED WITH SCOPES
App
Controller A
Stateless
service
Request Stack
Controller B
Sub
Request
Master
Request
REQUESTS MANAGED WITH STACK
FETCHING THE REQUEST FROM THE
STACK IS AN ANTI PATTERN
REQUEST INSTANCE
SHOULD BE PASSED AROUND
STATEFUL SERVICES
STATEFUL SERVICES
• Refactor & pass the state to the call
• Fetch state explicitly on per need basis
• Use shared = false flag
PROTOTYPE SCOPE
Prototype scope
Prototype-
scoped
Service Z
Stateless
Service A
Prototype scope
Prototype-
scoped
Service Z
Stateless
Service A
Prototype scope
Prototype-
scoped
Service Z
Stateless
Service A
USING PROTOTYPE SCOPE WITH STRICT = TRUE
New Instances
Stateful
Service Z
Stateful
Service Z
Stateful
Service Z
Stateless
Service A
USING PROTOTYPE SCOPE WITH STRICT = FALSE
FORGET ABOUT SCOPES ANYWAY
WERE REMOVED IN SYMFONY 3.0
USE SHARED=FALSE FLAG
CONTROLLERS
EXTENDING BASE CONTROLLER
• Easy to use by newcomers / low learning curve
• Limits inheritance
• Encourages using DIC as Service Locator
• Hard unit testing
CONTAINER AWARE INTERFACE
• Controller is still coupled to framework
• Enables inheritance
• Lack of convenience methods
• Encourages using DIC as Service Locator
• Testing is still hard
CONTROLLER AS A SERVICE
• Requires additional configuration
• Lack of convenience methods
• Full possibility to inject only relevant dependencies
• Unit testing is easy
• Enables Framework-agnostic controllers
NONE OF THE ABOVE OPTIONS WILL
FORCE YOU TO WRITE GOOD/BAD CODE
SYMFONY/EVENT-DISPATCHER
FEATURES
• Implementation of Mediator pattern
• Allows for many-to-many relationships between objects
• Makes your projects extensible
• Supports priorities/stopping event flow
EVENT DISPATCHER
• Can be (really) hard to debug
• Priorities of events / managing event flow
• Events can be mutable - indirect coupling
• Hard to test
INDIRECT COUPLING PROBLEM
• Two services listening on kernel.request event:
• Priority 16 - GeoIP detector - sets country code
• Priority 8 - Locale detector - uses country code and
user agent
INDIRECT COUPLING PROBLEM
• Both events indirectly coupled (via Request->attributes)
• Configuration change will change the app logic
• In reality we always want to call one after another
WHEN TO USE EVENT DISPATCHER
• Need to extend Framework or other Bundle
• Building reusable Bundle & need to add extension points
• Consider using separate dispatcher for Domain events
CHAPTER 4: THE END ;)
BE PRAGMATIC
BE EXPLICIT
DON’T RELY ON MAGIC
Kacper Gunia @cakper
Independent Consultant & Trainer
DDD London Leader
Thanks!
joind.in/talk/f681d
REFERENCES
• http://martinfowler.com/bliki/InversionOfControl.html
• http://picocontainer.com/introduction.html
• http://www.infoq.com/presentations/8-lines-code-refactoring
• http://richardmiller.co.uk/2014/03/12/avoiding-setter-injection/
• http://art-of-software.blogspot.co.uk/2013/02/cztery-smaki-
odwracania-i-utraty.html

Más contenido relacionado

La actualidad más candente

Decoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DICDecoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DICKonstantin Kudryashov
 
Scaling Symfony2 apps with RabbitMQ - Symfony UK Meetup
Scaling Symfony2 apps with RabbitMQ - Symfony UK MeetupScaling Symfony2 apps with RabbitMQ - Symfony UK Meetup
Scaling Symfony2 apps with RabbitMQ - Symfony UK MeetupKacper Gunia
 
Design Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleDesign Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleHugo Hamon
 
Rich Model And Layered Architecture in SF2 Application
Rich Model And Layered Architecture in SF2 ApplicationRich Model And Layered Architecture in SF2 Application
Rich Model And Layered Architecture in SF2 ApplicationKirill Chebunin
 
Models and Service Layers, Hemoglobin and Hobgoblins
Models and Service Layers, Hemoglobin and HobgoblinsModels and Service Layers, Hemoglobin and Hobgoblins
Models and Service Layers, Hemoglobin and HobgoblinsRoss Tuck
 
Silex meets SOAP & REST
Silex meets SOAP & RESTSilex meets SOAP & REST
Silex meets SOAP & RESTHugo Hamon
 
The History of PHPersistence
The History of PHPersistenceThe History of PHPersistence
The History of PHPersistenceHugo Hamon
 
Database Design Patterns
Database Design PatternsDatabase Design Patterns
Database Design PatternsHugo Hamon
 
Min-Maxing Software Costs - Laracon EU 2015
Min-Maxing Software Costs - Laracon EU 2015Min-Maxing Software Costs - Laracon EU 2015
Min-Maxing Software Costs - Laracon EU 2015Konstantin Kudryashov
 
Decoupling the Ulabox.com monolith. From CRUD to DDD
Decoupling the Ulabox.com monolith. From CRUD to DDDDecoupling the Ulabox.com monolith. From CRUD to DDD
Decoupling the Ulabox.com monolith. From CRUD to DDDAleix Vergés
 
Design how your objects talk through mocking
Design how your objects talk through mockingDesign how your objects talk through mocking
Design how your objects talk through mockingKonstantin Kudryashov
 
Command Bus To Awesome Town
Command Bus To Awesome TownCommand Bus To Awesome Town
Command Bus To Awesome TownRoss Tuck
 
PHPCon 2016: PHP7 by Witek Adamus / XSolve
PHPCon 2016: PHP7 by Witek Adamus / XSolvePHPCon 2016: PHP7 by Witek Adamus / XSolve
PHPCon 2016: PHP7 by Witek Adamus / XSolveXSolve
 
PHP 5.3 and Lithium: the most rad php framework
PHP 5.3 and Lithium: the most rad php frameworkPHP 5.3 and Lithium: the most rad php framework
PHP 5.3 and Lithium: the most rad php frameworkG Woo
 
Doctrine fixtures
Doctrine fixturesDoctrine fixtures
Doctrine fixturesBill Chang
 
Speed up your developments with Symfony2
Speed up your developments with Symfony2Speed up your developments with Symfony2
Speed up your developments with Symfony2Hugo Hamon
 
The Zen of Lithium
The Zen of LithiumThe Zen of Lithium
The Zen of LithiumNate Abele
 
PhpSpec 2.0 ilustrated by examples
PhpSpec 2.0 ilustrated by examplesPhpSpec 2.0 ilustrated by examples
PhpSpec 2.0 ilustrated by examplesMarcello Duarte
 
Dependency Injection in PHP
Dependency Injection in PHPDependency Injection in PHP
Dependency Injection in PHPKacper Gunia
 

La actualidad más candente (20)

Decoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DICDecoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DIC
 
Scaling Symfony2 apps with RabbitMQ - Symfony UK Meetup
Scaling Symfony2 apps with RabbitMQ - Symfony UK MeetupScaling Symfony2 apps with RabbitMQ - Symfony UK Meetup
Scaling Symfony2 apps with RabbitMQ - Symfony UK Meetup
 
Design Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleDesign Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et Pimple
 
Rich Model And Layered Architecture in SF2 Application
Rich Model And Layered Architecture in SF2 ApplicationRich Model And Layered Architecture in SF2 Application
Rich Model And Layered Architecture in SF2 Application
 
Min-Maxing Software Costs
Min-Maxing Software CostsMin-Maxing Software Costs
Min-Maxing Software Costs
 
Models and Service Layers, Hemoglobin and Hobgoblins
Models and Service Layers, Hemoglobin and HobgoblinsModels and Service Layers, Hemoglobin and Hobgoblins
Models and Service Layers, Hemoglobin and Hobgoblins
 
Silex meets SOAP & REST
Silex meets SOAP & RESTSilex meets SOAP & REST
Silex meets SOAP & REST
 
The History of PHPersistence
The History of PHPersistenceThe History of PHPersistence
The History of PHPersistence
 
Database Design Patterns
Database Design PatternsDatabase Design Patterns
Database Design Patterns
 
Min-Maxing Software Costs - Laracon EU 2015
Min-Maxing Software Costs - Laracon EU 2015Min-Maxing Software Costs - Laracon EU 2015
Min-Maxing Software Costs - Laracon EU 2015
 
Decoupling the Ulabox.com monolith. From CRUD to DDD
Decoupling the Ulabox.com monolith. From CRUD to DDDDecoupling the Ulabox.com monolith. From CRUD to DDD
Decoupling the Ulabox.com monolith. From CRUD to DDD
 
Design how your objects talk through mocking
Design how your objects talk through mockingDesign how your objects talk through mocking
Design how your objects talk through mocking
 
Command Bus To Awesome Town
Command Bus To Awesome TownCommand Bus To Awesome Town
Command Bus To Awesome Town
 
PHPCon 2016: PHP7 by Witek Adamus / XSolve
PHPCon 2016: PHP7 by Witek Adamus / XSolvePHPCon 2016: PHP7 by Witek Adamus / XSolve
PHPCon 2016: PHP7 by Witek Adamus / XSolve
 
PHP 5.3 and Lithium: the most rad php framework
PHP 5.3 and Lithium: the most rad php frameworkPHP 5.3 and Lithium: the most rad php framework
PHP 5.3 and Lithium: the most rad php framework
 
Doctrine fixtures
Doctrine fixturesDoctrine fixtures
Doctrine fixtures
 
Speed up your developments with Symfony2
Speed up your developments with Symfony2Speed up your developments with Symfony2
Speed up your developments with Symfony2
 
The Zen of Lithium
The Zen of LithiumThe Zen of Lithium
The Zen of Lithium
 
PhpSpec 2.0 ilustrated by examples
PhpSpec 2.0 ilustrated by examplesPhpSpec 2.0 ilustrated by examples
PhpSpec 2.0 ilustrated by examples
 
Dependency Injection in PHP
Dependency Injection in PHPDependency Injection in PHP
Dependency Injection in PHP
 

Destacado

Machine learning for developers
Machine learning for developersMachine learning for developers
Machine learning for developersSource Ministry
 
Holistic approach to machine learning
Holistic approach to machine learningHolistic approach to machine learning
Holistic approach to machine learningSource Ministry
 
Embrace Events and let CRUD die
Embrace Events and let CRUD dieEmbrace Events and let CRUD die
Embrace Events and let CRUD dieKacper Gunia
 
The top 10 things that any pro PHP developer should be doing
The top 10 things that any pro PHP developer should be doingThe top 10 things that any pro PHP developer should be doing
The top 10 things that any pro PHP developer should be doingKacper Gunia
 
Service discovery and configuration provisioning
Service discovery and configuration provisioningService discovery and configuration provisioning
Service discovery and configuration provisioningSource Ministry
 

Destacado (7)

Machine learning for developers
Machine learning for developersMachine learning for developers
Machine learning for developers
 
Holistic approach to machine learning
Holistic approach to machine learningHolistic approach to machine learning
Holistic approach to machine learning
 
Embrace Events and let CRUD die
Embrace Events and let CRUD dieEmbrace Events and let CRUD die
Embrace Events and let CRUD die
 
MySQL under the siege
MySQL under the siegeMySQL under the siege
MySQL under the siege
 
The top 10 things that any pro PHP developer should be doing
The top 10 things that any pro PHP developer should be doingThe top 10 things that any pro PHP developer should be doing
The top 10 things that any pro PHP developer should be doing
 
Time series databases
Time series databasesTime series databases
Time series databases
 
Service discovery and configuration provisioning
Service discovery and configuration provisioningService discovery and configuration provisioning
Service discovery and configuration provisioning
 

Similar a The IoC Hydra - Dutch PHP Conference 2016

Symfony2 from the Trenches
Symfony2 from the TrenchesSymfony2 from the Trenches
Symfony2 from the TrenchesJonathan Wage
 
Singletons in PHP - Why they are bad and how you can eliminate them from your...
Singletons in PHP - Why they are bad and how you can eliminate them from your...Singletons in PHP - Why they are bad and how you can eliminate them from your...
Singletons in PHP - Why they are bad and how you can eliminate them from your...go_oh
 
How Kris Writes Symfony Apps
How Kris Writes Symfony AppsHow Kris Writes Symfony Apps
How Kris Writes Symfony AppsKris Wallsmith
 
Symfony2 - from the trenches
Symfony2 - from the trenchesSymfony2 - from the trenches
Symfony2 - from the trenchesLukas Smith
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For BeginnersJonathan Wage
 
Modularity and Layered Data Model
Modularity and Layered Data ModelModularity and Layered Data Model
Modularity and Layered Data ModelAttila Jenei
 
Inversion Of Control
Inversion Of ControlInversion Of Control
Inversion Of ControlChad Hietala
 
Domain Driven Design using Laravel
Domain Driven Design using LaravelDomain Driven Design using Laravel
Domain Driven Design using Laravelwajrcs
 
PHP: 4 Design Patterns to Make Better Code
PHP: 4 Design Patterns to Make Better CodePHP: 4 Design Patterns to Make Better Code
PHP: 4 Design Patterns to Make Better CodeSWIFTotter Solutions
 
Dependency injection in Drupal 8
Dependency injection in Drupal 8Dependency injection in Drupal 8
Dependency injection in Drupal 8Alexei Gorobets
 
A resource oriented framework using the DI/AOP/REST triangle
A resource oriented framework using the DI/AOP/REST triangleA resource oriented framework using the DI/AOP/REST triangle
A resource oriented framework using the DI/AOP/REST triangleAkihito Koriyama
 
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...ZFConf Conference
 
ZF2 for the ZF1 Developer
ZF2 for the ZF1 DeveloperZF2 for the ZF1 Developer
ZF2 for the ZF1 DeveloperGary Hockin
 
Lithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate FrameworksLithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate FrameworksNate Abele
 
Symfony War Stories
Symfony War StoriesSymfony War Stories
Symfony War StoriesJakub Zalas
 
What's New In Laravel 5
What's New In Laravel 5What's New In Laravel 5
What's New In Laravel 5Darren Craig
 

Similar a The IoC Hydra - Dutch PHP Conference 2016 (20)

Symfony2 from the Trenches
Symfony2 from the TrenchesSymfony2 from the Trenches
Symfony2 from the Trenches
 
Singletons in PHP - Why they are bad and how you can eliminate them from your...
Singletons in PHP - Why they are bad and how you can eliminate them from your...Singletons in PHP - Why they are bad and how you can eliminate them from your...
Singletons in PHP - Why they are bad and how you can eliminate them from your...
 
How Kris Writes Symfony Apps
How Kris Writes Symfony AppsHow Kris Writes Symfony Apps
How Kris Writes Symfony Apps
 
Symfony2 - from the trenches
Symfony2 - from the trenchesSymfony2 - from the trenches
Symfony2 - from the trenches
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For Beginners
 
Modularity and Layered Data Model
Modularity and Layered Data ModelModularity and Layered Data Model
Modularity and Layered Data Model
 
Inversion Of Control
Inversion Of ControlInversion Of Control
Inversion Of Control
 
Domain Driven Design using Laravel
Domain Driven Design using LaravelDomain Driven Design using Laravel
Domain Driven Design using Laravel
 
PHP: 4 Design Patterns to Make Better Code
PHP: 4 Design Patterns to Make Better CodePHP: 4 Design Patterns to Make Better Code
PHP: 4 Design Patterns to Make Better Code
 
Dependency injection in Drupal 8
Dependency injection in Drupal 8Dependency injection in Drupal 8
Dependency injection in Drupal 8
 
Design Patterns
Design PatternsDesign Patterns
Design Patterns
 
A resource oriented framework using the DI/AOP/REST triangle
A resource oriented framework using the DI/AOP/REST triangleA resource oriented framework using the DI/AOP/REST triangle
A resource oriented framework using the DI/AOP/REST triangle
 
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
 
ZF2 for the ZF1 Developer
ZF2 for the ZF1 DeveloperZF2 for the ZF1 Developer
ZF2 for the ZF1 Developer
 
Dependency Injection
Dependency InjectionDependency Injection
Dependency Injection
 
AngularJs
AngularJsAngularJs
AngularJs
 
Lithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate FrameworksLithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate Frameworks
 
Symfony War Stories
Symfony War StoriesSymfony War Stories
Symfony War Stories
 
What's New In Laravel 5
What's New In Laravel 5What's New In Laravel 5
What's New In Laravel 5
 
Make it SOLID!
Make it SOLID!Make it SOLID!
Make it SOLID!
 

Más de Kacper Gunia

How a large corporation used Domain-Driven Design to replace a loyalty system
How a large corporation used Domain-Driven Design to replace a loyalty systemHow a large corporation used Domain-Driven Design to replace a loyalty system
How a large corporation used Domain-Driven Design to replace a loyalty systemKacper Gunia
 
Rebuilding Legacy Apps with Domain-Driven Design - Lessons learned
Rebuilding Legacy Apps with Domain-Driven Design - Lessons learnedRebuilding Legacy Apps with Domain-Driven Design - Lessons learned
Rebuilding Legacy Apps with Domain-Driven Design - Lessons learnedKacper Gunia
 
Domain-driven Design in PHP and Symfony - Drupal Camp Wroclaw!
Domain-driven Design in PHP and Symfony - Drupal Camp Wroclaw!Domain-driven Design in PHP and Symfony - Drupal Camp Wroclaw!
Domain-driven Design in PHP and Symfony - Drupal Camp Wroclaw!Kacper Gunia
 
OmniFocus - the #1 ‘Getting Things Done’ tool
OmniFocus - the #1 ‘Getting Things Done’ toolOmniFocus - the #1 ‘Getting Things Done’ tool
OmniFocus - the #1 ‘Getting Things Done’ toolKacper Gunia
 

Más de Kacper Gunia (6)

How a large corporation used Domain-Driven Design to replace a loyalty system
How a large corporation used Domain-Driven Design to replace a loyalty systemHow a large corporation used Domain-Driven Design to replace a loyalty system
How a large corporation used Domain-Driven Design to replace a loyalty system
 
Rebuilding Legacy Apps with Domain-Driven Design - Lessons learned
Rebuilding Legacy Apps with Domain-Driven Design - Lessons learnedRebuilding Legacy Apps with Domain-Driven Design - Lessons learned
Rebuilding Legacy Apps with Domain-Driven Design - Lessons learned
 
Domain-driven Design in PHP and Symfony - Drupal Camp Wroclaw!
Domain-driven Design in PHP and Symfony - Drupal Camp Wroclaw!Domain-driven Design in PHP and Symfony - Drupal Camp Wroclaw!
Domain-driven Design in PHP and Symfony - Drupal Camp Wroclaw!
 
OmniFocus - the #1 ‘Getting Things Done’ tool
OmniFocus - the #1 ‘Getting Things Done’ toolOmniFocus - the #1 ‘Getting Things Done’ tool
OmniFocus - the #1 ‘Getting Things Done’ tool
 
Code Dojo
Code DojoCode Dojo
Code Dojo
 
SpecBDD in PHP
SpecBDD in PHPSpecBDD in PHP
SpecBDD in PHP
 

Último

Pigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsMemoori
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Patryk Bandurski
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking MenDelhi Call girls
 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptxLBM Solutions
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j
 
How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?XfilesPro
 
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphSIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphNeo4j
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
Pigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Paola De la Torre
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxKatpro Technologies
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 

Último (20)

Pigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping Elbows
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial Buildings
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptx
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
 
How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?
 
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphSIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
Pigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food Manufacturing
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 

The IoC Hydra - Dutch PHP Conference 2016

  • 2. Kacper Gunia @cakper Independent Consultant & Trainer DDD London Leader @ddd_london
  • 3. CHAPTER 1: THE THEORY
  • 4. THIS IS NOT YET ANOTHER DEPENDENCY INJECTION TALK ;)
  • 5. SO WE NEED SOME CLARIFICATION
  • 7. –Pico Container “Inversion of Control (IoC) is a design pattern that addresses a component’s dependency resolution, configuration and lifecycle. ”
  • 8. –Pico Container “It suggests that the control of those three should not be the concern of the component itself. Thus it is inverted back.”
  • 9. –Pico Container “Dependency Injection is where components are given their dependencies through their constructors, methods, or directly into fields.”
  • 11. WHY DO WE IOC?
  • 12. PROS • Separation of concerns: • dependency resolution, configuration and lifecycle • Enforcing Single Responsibility Principle • Easier testing • Modular architecture, loose coupling
  • 13. CONS • Learning curve • Code is harder do analyse/debug • Moves complexity somewhere else (doesn’t remove) • Need for extra tools like Containers / Dispatchers
  • 14. HOW DO WE WRITE SOFTWARE WITHOUT IOC?
  • 16. EXAMPLE interface Logger
 {
 public function log($log);
 }
 
 class PrintingLogger implements Logger
 {
 public function log($log)
 {
 echo $log;
 }
 }
  • 17. EXAMPLE class LocalFileEraser implements FileEraser
 {
 public function erase($filename) {
 $logger = new PrintingLogger();
 $logger->log("Attempt to erase file: " . $filename);
 
 unlink($filename);
 
 $logger->log("File " . $filename . " was erased.”);
 }
 }
  • 18. EXAMPLE $eraser = new LocalFileEraser();
 $eraser->erase('important-passwords.txt');
  • 19. HOW CAN WE FIX IT WITH DI?
  • 20. EXAMPLE WITH DI class LocalFileEraser implements FileEraser {
 private $logger;
 
 public function __construct(Logger $logger) {
 $this->logger = $logger;
 }
 
 public function erase($path) {
 $this->logger->log("Attempt to erase file: " . $path); 
 unlink($path); 
 $this->logger->log("File " . $path . " was erased.");
 }
 }
  • 21. EXAMPLE WITH DI $logger = new PrintingLogger();
 $eraser = new LocalFileEraser($logger);
 
 $eraser->erase('important-passwords.txt');
  • 22. What (is being executed) Known Unknown KnownUnknown When(isbeingexecuted) Dependency Injection Stages of loosening control (from the component point of view)
  • 23. HOW CAN WE FIX IT WITH EVENTS?
  • 24. EXAMPLE WITH EVENTS class FileEvent implements Event
 {
 private $path;
 public function __construct($path)
 {
 $this->path = $path;
 }
 
 public function getPath()
 {
 return $this->path;
 }
 }
  • 25. EXAMPLE WITH EVENTS class FileEraseWasInitialised extends FileEvent
 {
 
 }
 
 class FileWasErased extends FileEvent
 {
 
 }
  • 26. EXAMPLE WITH EVENTS interface Listener
 {
 public function handle(Event $event);
 }
 
 interface Event
 {
 
 }
  • 27. EXAMPLE WITH EVENTS class LoggingFileEventListener implements Listener
 {
 private $logger;
 
 public function __construct(Logger $logger)
 {
 $this->logger = $logger;
 }
 
 public function handle(Event $event)
 {
 if ($event instanceof FileEvent) {
 $this->logger->log(get_class($event).' '.$event->getPath());
 }
 }
 }
  • 28. EXAMPLE WITH EVENTS trait Observable
 {
 private $listeners = [];
 
 public function addListener(Listener $listener)
 {
 $this->listeners[] = $listener;
 }
 
 public function dispatch(Event $event)
 {
 foreach ($this->listeners as $listener) {
 $listener->handle($event);
 }
 }
 }
  • 29. EXAMPLE WITH EVENTS class LocalFileEraser implements FileEraser
 {
 use Observable;
 
 public function erase($filename)
 {
 $this->dispatch(new FileEraseWasInitialised($filename));
 
 unlink($filename);
 
 $this->dispatch(new FileWasErased($filename));
 }
 }
  • 30. EXAMPLE WITH EVENTS $eraser = new LocalFileEraser();
 $listener = new LoggingFileEventListener(new PrintingLogger()); $eraser->addListener($listener);
 
 $eraser->erase('important-passwords.txt');
  • 31. What (is being executed) Known Unknown KnownUnknown When(isbeingexecuted) Events Stages of loosening control (from the component point of view)
  • 32. HOW CAN WE FIX IT WITH AOP?
  • 33. EXAMPLE WITH AOP USING DECORATOR class LocalFileEraser implements FileEraser
 {
 public function erase($filename)
 {
 unlink($filename);
 }
 }
  • 34. EXAMPLE WITH AOP USING DECORATOR class LoggingFileEraser implements FileEraser
 {
 private $decorated;
 
 private $logger;
 
 public function __construct(FileEraser $decorated, Logger $logger)
 {
 $this->decorated = $decorated;
 $this->logger = $logger;
 }
 
 public function erase($filename)
 {
 $this->logger->log('File erase was initialised' . $filename);
 
 $this->decorated->erase($filename);
 
 $this->logger->log('File was erased' . $filename);
 }
 }
  • 35. EXAMPLE WITH AOP USING DECORATOR $localFileEraser = new LocalFileEraser();
 $logger = new PrintingLogger();
 
 $eraser = new LoggingFileEraser($localFileEraser, $logger);
 
 $eraser->erase('important-passwords.txt');
  • 36. What (is being executed) Known Unknown KnownUnknown When(isbeingexecuted) AOP Stages of loosening control (from the component point of view)
  • 37. What (is being executed) Known Unknown KnownUnknown When(isbeingexecuted) Dependency Injection Events AOP Stages of loosening control (from the component point of view)
  • 39. A libraries provide functionality that you decide when to call.
  • 40. Frameworks provide an architecture for the application and decide when to call your code.
  • 41. “DON’T CALL US, WE’LL CALL YOU” aka Hollywood Principle
  • 42. Frameworks utilise IoC principles and can be seen as one of its manifestations.
  • 43. CHAPTER 2: THE PRACTICE
  • 46. RESOLVING GRAPHS OF OBJECTS $dsn = 'mysql:host=localhost;dbname=testdb;charset=utf8';
 $dbUsername = 'username';
 $dbPassword = 'password';
 $customerRepository = new CustomerRepository(new PDO($dsn, $dbUsername, $dbPassword));
 
 $smtpHost = 'smtp.example.org';
 $smtpPort = 25;
 $smtpUsername = 'username';
 $smtpPassword = 'password';
 $transport = new Swift_SmtpTransport($smtpHost, $smtpPort);
 $transport->setUsername($smtpUsername);
 $transport->setPassword($smtpPassword);
 $mailer = new Swift_Mailer($transport);
 
 $loggerName = "App";
 $logger = new MonologLogger($loggerName);
 $stream = "app.log";
 $logger->pushHandler(new MonologHandlerStreamHandler($stream));
 
 $controller = new RegistrationController($customerRepository, $mailer, $logger);
  • 47. RESOLVING GRAPHS OF OBJECTS use PimpleContainer;
 
 $container = new Container();
 
 $container['dsn'] = 'mysql:host=localhost;dbname=testdb;charset=utf8';
 $container['db_username'] = 'username';
 $container['dsn'] = 'password';
 
 $container['pdo'] = function ($c) {
 return new PDO($c['dsn'], $c['db_username'], $c['dsn']);
 }; 
 $container['customer_repository'] = function ($c) {
 return new CustomerRepository($c['pdo']);
 };
  • 48. RESOLVING GRAPHS OF OBJECTS $container['smtp_host'] = 'smtp.example.org';
 $container['smtp_port'] = 25;
 $container['smtp_username'] = 'username';
 $container['smtp_password'] = 'password';
 
 $container['transport'] = function ($c) {
 return new Swift_SmtpTransport($c['smtp_host'], $c['smtp_port']);
 };
 
 $container->extend('transport', function ($transport, $c) {
 $transport->setUsername($c['smtp_username']);
 $transport->setPassword($c['smtp_password']);
 
 return $transport;
 });
 
 $container['mailer'] = function ($c) {
 return new Swift_Mailer($c['transport']);
 };
  • 49. RESOLVING GRAPHS OF OBJECTS $container['logger_name'] = "App";
 $container['stream_name'] = "app_" . $container['environment'] . ".log";
 
 $container['logger'] = function ($c) {
 return new MonologLogger($c['logger_name']);
 };
 
 $container->extend('transport', function ($logger, $c) {
 $logger->pushHandler( new MonologHandlerStreamHandler($c[‘stream_handler']) );
 
 return $logger;
 });
 
 $container['stream_handler'] = function ($c) {
 return new MonologHandlerStreamHandler($c['stream_name']);
 };
  • 50. RESOLVING GRAPHS OF OBJECTS $container['registration_controller'] = function ($c) {
 return new RegistrationController( $c['customer_repository'], $c['mailer'], $c[‘logger’] );
 };
  • 51. LIFECYCLE MANAGEMENT $container['session_storage'] = function ($c) {
 return new SessionStorage('SESSION_ID');
 };
  • 52. LIFECYCLE MANAGEMENT $container['session_storage'] = $container->factory(function ($c) {
 return new SessionStorage('SESSION_ID');
 });
  • 54. SERVICE LOCATOR class RegistrationController {
 function resetPasswordAction() {
 $mailer = Container::instance()['mailer'];
 //...
 }
 }
  • 55. SERVICE LOCATOR • Coupled to container • Responsible for resolving dependencies • Dependencies are hidden • Hard to test • Might be ok when modernising legacy!
  • 57. SETTER INJECTION • Forces to be defensive as dependencies are optional • Dependency is not locked (mutable) • In some cases can be replaced with events • We can avoid it by using NullObject pattern
  • 58. SETTER INJECTION class LocalFileEraser implements FileEraser
 {
 private $logger;
 
 public function setLogger(Logger $logger)
 {
 $this->logger = $logger;
 }
 
 public function erase($filename)
 {
 if ($this->logger instanceof Logger) {
 $this->logger->log("Attempt to erase file: " . $filename);
 }
 
 unlink($filename);
 
 if ($this->logger instanceof Logger) {
 $this->logger->log("File " . $filename . " was deleted");
 }
 }
 }
  • 59. SETTER INJECTION class LocalFileEraser implements FileEraser
 {
 private $logger;
 
 public function __construct(Logger $logger)
 {
 $this->logger = $logger;
 }
 
 public function erase($path)
 {
 $this->logger->log("Attempt to erase file: " . $path);
 
 unlink($path);
 
 $this->logger->log("File " . $path . " was erased.”);
 }
 }
  • 60. SETTER INJECTION class NullLogger implements Logger {
 
 public function log($log)
 {
 // whateva...
 }
 }
 
 $eraser = new LocalFileEraser(new NullLogger());
 $eraser->erase('important-passwords.txt');
  • 62. DI WAY OF DOING THINGS interface Logger
 {
 public function log($log);
 }
 
 class PrintingLogger implements Logger
 {
 public function log($log)
 {
 echo $log;
 }
 }
  • 63. DI WAY OF DOING THINGS class LocalFileEraser implements FileEraser
 {
 private $logger;
 
 public function __construct(Logger $logger)
 {
 $this->logger = $logger;
 }
 
 public function erase($path)
 {
 $this->logger->log("Attempt to erase file: " . $path);
 
 unlink($path);
 
 $this->logger->log("File " . $path . " was deleted");
 }
 }
  • 64. DI WAY OF DOING THINGS $logger = new PrintingLogger();
 $eraser = new LocalFileEraser($logger);
 
 $eraser->erase('important-passwords.txt');
  • 65. FUNCTIONAL WAY OF DOING THINGS $erase = function (Logger $logger, $path)
 {
 $logger->log("Attempt to erase file: " . $path);
 unlink($path);
 $logger->log("File " . $path . " was deleted");
 };
  • 66. FUNCTIONAL WAY OF DOING THINGS use ReactPartial; 
 $erase = function (Logger $logger, $path)
 {
 $logger->log("Attempt to erase file: " . $path);
 unlink($path);
 $logger->log("File " . $path . " was deleted");
 };
 
 $erase = Partialbind($erase, new PrintingLogger()); 
 $erase('important-passwords.txt');
  • 67. CHAPTER 3: THE SYMFONY
  • 69. FEATURES • Many configurations formats • Supports Factories/Configurators/Decoration • Extendable with Compiler Passes • Supports lazy loading of services
  • 71. PERFORMANCE OF SYMFONY DIC • Cached/Dumped to PHP code • In debug mode it checks whether config is fresh • During Compilation phase container is being optimised
  • 72. LARGE NUMBER OF CONFIGURATION FILES SLOWS CONTAINER BUILDER
  • 73.
  • 74. SLOW COMPILATION • Minimise number of bundles/config files used • Try to avoid using extras like JMSDiExtraBundle • Can be really painful on NFS
  • 75. LARGE CONTAINERS ARE SLOW TO LOAD AND USE A LOT OF MEMORY
  • 76. LARGE CONTAINERS • Review and remove unnecessary services/bundles etc. • Split application into smaller ones with separate kernels
  • 78.
  • 79. PRIVATE SERVICES • It’s only a hint for compiler • Minor performance gain (inlines instantiation) • Private services can still be fetched (not recommended)
  • 80. LAZY LOADING OF SERVICES
  • 81. LAZY LOADING OF SERVICES • Used when instantiation is expensive or not needed • i.e. event listeners • Solutions: • Injecting container directly • Using proxy objects
  • 82. INJECTING CONTAINER DIRECTLY • As fast as it can be • Couples service implementation to the container • Makes testing harder
  • 83. USING PROXY OBJECTS • Easy to use (just configuration option) • Code and test are not affected • Adds a bit of overhead • especially when services are called many times • on proxy generation
  • 85. DEFINING CLASS NAMES AS PARAMETERS • Rare use case (since decoration is supported even less) • Adds overhead • Removed in Symfony 3.0
  • 87.
  • 89. CIRCULAR REFERENCES • Injecting Container is just a workaround • Using setter injection after instantiation as well • Solving design problem is the real challenge
  • 92. MEANT TO SOLVE “THE REQUEST PROBLEM”
  • 93. SCOPE DEFINES STATE OF THE APPLICATION
  • 95. PROBLEMS WITH INJECTING REQUEST TO SERVICES • Causes ScopeWideningInjectionException • Anti-pattern - Request is a Value Object • Which means Container was managing it’s state • Replaced with RequestStack
  • 96. App Controller A Sub Request Stateful service Sub Request Master Request Stateful service Master Request Controller B REQUESTS MANAGED WITH SCOPES
  • 97. App Controller A Stateless service Request Stack Controller B Sub Request Master Request REQUESTS MANAGED WITH STACK
  • 98. FETCHING THE REQUEST FROM THE STACK IS AN ANTI PATTERN
  • 99. REQUEST INSTANCE SHOULD BE PASSED AROUND
  • 101.
  • 102. STATEFUL SERVICES • Refactor & pass the state to the call • Fetch state explicitly on per need basis • Use shared = false flag
  • 104.
  • 105. Prototype scope Prototype- scoped Service Z Stateless Service A Prototype scope Prototype- scoped Service Z Stateless Service A Prototype scope Prototype- scoped Service Z Stateless Service A USING PROTOTYPE SCOPE WITH STRICT = TRUE
  • 106. New Instances Stateful Service Z Stateful Service Z Stateful Service Z Stateless Service A USING PROTOTYPE SCOPE WITH STRICT = FALSE
  • 107. FORGET ABOUT SCOPES ANYWAY WERE REMOVED IN SYMFONY 3.0
  • 110.
  • 111. EXTENDING BASE CONTROLLER • Easy to use by newcomers / low learning curve • Limits inheritance • Encourages using DIC as Service Locator • Hard unit testing
  • 112. CONTAINER AWARE INTERFACE • Controller is still coupled to framework • Enables inheritance • Lack of convenience methods • Encourages using DIC as Service Locator • Testing is still hard
  • 113. CONTROLLER AS A SERVICE • Requires additional configuration • Lack of convenience methods • Full possibility to inject only relevant dependencies • Unit testing is easy • Enables Framework-agnostic controllers
  • 114. NONE OF THE ABOVE OPTIONS WILL FORCE YOU TO WRITE GOOD/BAD CODE
  • 116. FEATURES • Implementation of Mediator pattern • Allows for many-to-many relationships between objects • Makes your projects extensible • Supports priorities/stopping event flow
  • 117. EVENT DISPATCHER • Can be (really) hard to debug • Priorities of events / managing event flow • Events can be mutable - indirect coupling • Hard to test
  • 118. INDIRECT COUPLING PROBLEM • Two services listening on kernel.request event: • Priority 16 - GeoIP detector - sets country code • Priority 8 - Locale detector - uses country code and user agent
  • 119. INDIRECT COUPLING PROBLEM • Both events indirectly coupled (via Request->attributes) • Configuration change will change the app logic • In reality we always want to call one after another
  • 120.
  • 121. WHEN TO USE EVENT DISPATCHER • Need to extend Framework or other Bundle • Building reusable Bundle & need to add extension points • Consider using separate dispatcher for Domain events
  • 122. CHAPTER 4: THE END ;)
  • 125. DON’T RELY ON MAGIC
  • 126. Kacper Gunia @cakper Independent Consultant & Trainer DDD London Leader Thanks! joind.in/talk/f681d
  • 127. REFERENCES • http://martinfowler.com/bliki/InversionOfControl.html • http://picocontainer.com/introduction.html • http://www.infoq.com/presentations/8-lines-code-refactoring • http://richardmiller.co.uk/2014/03/12/avoiding-setter-injection/ • http://art-of-software.blogspot.co.uk/2013/02/cztery-smaki- odwracania-i-utraty.html