The IoC Hydra

Kacper Gunia
Kacper GuniaIndependent Software Consultant & Trainer at Domain Centric
The IoC Hydra
Kacper Gunia @cakper
Technical Team Leader @SensioLabsUK
Symfony Certified Developer
PHPers Silesia @PHPersPL
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
interface Listener

{

public function handle(Event $event);

}



interface Event

{



}
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
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/Scopes/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
The IoC Hydra
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
The IoC Hydra
PRIVATE SERVICES
• It’s only a hint for compiler
• Minor performance gain (inlines instations)
• 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
• Will be removed in Symfony 3.0
CIRCULAR REFERENCES
The IoC Hydra
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
STATEFUL SERVICES
The IoC Hydra
STATEFUL SERVICES
• Fetch state explicitly on per need basis (RequestStack)
• Use Prototype scope only if you have to…
PROTOTYPE SCOPE
The IoC Hydra
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
WILL BE REMOVED IN SYMFONY 3.0
USE SHARED=FALSE INSTEAD
CONTROLLERS
The IoC Hydra
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
• 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
Listener A
Listener B
Listener C
DispatcherService
INDIRECT COUPLING PROBLEM
The IoC Hydra
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
Technical Team Leader @SensioLabsUK
Symfony Certified Developer
PHPers Silesia @PHPersPL
Thanks!
https://joind.in/14979
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
1 of 124

Recommended

The IoC Hydra - Dutch PHP Conference 2016 by
The IoC Hydra - Dutch PHP Conference 2016The IoC Hydra - Dutch PHP Conference 2016
The IoC Hydra - Dutch PHP Conference 2016Kacper Gunia
1.2K views127 slides
Forget about index.php and build you applications around HTTP! by
Forget about index.php and build you applications around HTTP!Forget about index.php and build you applications around HTTP!
Forget about index.php and build you applications around HTTP!Kacper Gunia
5.7K views128 slides
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you need by
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you needDutch PHP Conference - PHPSpec 2 - The only Design Tool you need
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you needKacper Gunia
50.4K views140 slides
Rich domain model with symfony 2.5 and doctrine 2.5 by
Rich domain model with symfony 2.5 and doctrine 2.5Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Leonardo Proietti
12K views90 slides
Forget about Index.php and build you applications around HTTP - PHPers Cracow by
Forget about Index.php and build you applications around HTTP - PHPers CracowForget about Index.php and build you applications around HTTP - PHPers Cracow
Forget about Index.php and build you applications around HTTP - PHPers CracowKacper Gunia
3.2K views127 slides
PHPSpec - the only Design Tool you need - 4Developers by
PHPSpec - the only Design Tool you need - 4DevelopersPHPSpec - the only Design Tool you need - 4Developers
PHPSpec - the only Design Tool you need - 4DevelopersKacper Gunia
37.3K views137 slides

More Related Content

What's hot

Symfony2, creare bundle e valore per il cliente by
Symfony2, creare bundle e valore per il clienteSymfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il clienteLeonardo Proietti
1.3K views73 slides
Rich Model And Layered Architecture in SF2 Application by
Rich Model And Layered Architecture in SF2 ApplicationRich Model And Layered Architecture in SF2 Application
Rich Model And Layered Architecture in SF2 ApplicationKirill Chebunin
3.7K views36 slides
Min-Maxing Software Costs by
Min-Maxing Software CostsMin-Maxing Software Costs
Min-Maxing Software CostsKonstantin Kudryashov
879 views96 slides
Scaling Symfony2 apps with RabbitMQ - Symfony UK Meetup by
Scaling Symfony2 apps with RabbitMQ - Symfony UK MeetupScaling Symfony2 apps with RabbitMQ - Symfony UK Meetup
Scaling Symfony2 apps with RabbitMQ - Symfony UK MeetupKacper Gunia
25.5K views81 slides
Design how your objects talk through mocking by
Design how your objects talk through mockingDesign how your objects talk through mocking
Design how your objects talk through mockingKonstantin Kudryashov
6.2K views103 slides
Models and Service Layers, Hemoglobin and Hobgoblins by
Models and Service Layers, Hemoglobin and HobgoblinsModels and Service Layers, Hemoglobin and Hobgoblins
Models and Service Layers, Hemoglobin and HobgoblinsRoss Tuck
48.3K views284 slides

What's hot(20)

Symfony2, creare bundle e valore per il cliente by Leonardo Proietti
Symfony2, creare bundle e valore per il clienteSymfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il cliente
Leonardo Proietti1.3K views
Rich Model And Layered Architecture in SF2 Application by Kirill Chebunin
Rich Model And Layered Architecture in SF2 ApplicationRich Model And Layered Architecture in SF2 Application
Rich Model And Layered Architecture in SF2 Application
Kirill Chebunin3.7K views
Scaling Symfony2 apps with RabbitMQ - Symfony UK Meetup by Kacper Gunia
Scaling Symfony2 apps with RabbitMQ - Symfony UK MeetupScaling Symfony2 apps with RabbitMQ - Symfony UK Meetup
Scaling Symfony2 apps with RabbitMQ - Symfony UK Meetup
Kacper Gunia25.5K views
Models and Service Layers, Hemoglobin and Hobgoblins by Ross Tuck
Models and Service Layers, Hemoglobin and HobgoblinsModels and Service Layers, Hemoglobin and Hobgoblins
Models and Service Layers, Hemoglobin and Hobgoblins
Ross Tuck48.3K views
Design Patterns avec PHP 5.3, Symfony et Pimple by Hugo Hamon
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
Hugo Hamon6.1K views
Dependency Injection in PHP by Kacper Gunia
Dependency Injection in PHPDependency Injection in PHP
Dependency Injection in PHP
Kacper Gunia1.9M views
Decoupling the Ulabox.com monolith. From CRUD to DDD by Aleix Vergés
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
Aleix Vergés1.8K views
When cqrs meets event sourcing by Manel Sellés
When cqrs meets event sourcingWhen cqrs meets event sourcing
When cqrs meets event sourcing
Manel Sellés4.3K views
PHPCon 2016: PHP7 by Witek Adamus / XSolve by XSolve
PHPCon 2016: PHP7 by Witek Adamus / XSolvePHPCon 2016: PHP7 by Witek Adamus / XSolve
PHPCon 2016: PHP7 by Witek Adamus / XSolve
XSolve1K views
Silex meets SOAP & REST by Hugo Hamon
Silex meets SOAP & RESTSilex meets SOAP & REST
Silex meets SOAP & REST
Hugo Hamon14.8K views
Database Design Patterns by Hugo Hamon
Database Design PatternsDatabase Design Patterns
Database Design Patterns
Hugo Hamon11.4K views
Crafting beautiful software by Jorn Oomen
Crafting beautiful softwareCrafting beautiful software
Crafting beautiful software
Jorn Oomen2K views
The History of PHPersistence by Hugo Hamon
The History of PHPersistenceThe History of PHPersistence
The History of PHPersistence
Hugo Hamon2.3K views
Command Bus To Awesome Town by Ross Tuck
Command Bus To Awesome TownCommand Bus To Awesome Town
Command Bus To Awesome Town
Ross Tuck7.2K views
Speed up your developments with Symfony2 by Hugo Hamon
Speed up your developments with Symfony2Speed up your developments with Symfony2
Speed up your developments with Symfony2
Hugo Hamon4.5K views
Doctrine fixtures by Bill Chang
Doctrine fixturesDoctrine fixtures
Doctrine fixtures
Bill Chang5K views
Beyond symfony 1.2 (Symfony Camp 2008) by Fabien Potencier
Beyond symfony 1.2 (Symfony Camp 2008)Beyond symfony 1.2 (Symfony Camp 2008)
Beyond symfony 1.2 (Symfony Camp 2008)
Fabien Potencier58.8K views

Viewers also liked

Zephir - A Wind of Change for writing PHP extensions by
Zephir - A Wind of Change for writing PHP extensionsZephir - A Wind of Change for writing PHP extensions
Zephir - A Wind of Change for writing PHP extensionsMark Baker
2.1K views53 slides
Enterprise Architecture Case in PHP (MUZIK Online) by
Enterprise Architecture Case in PHP (MUZIK Online)Enterprise Architecture Case in PHP (MUZIK Online)
Enterprise Architecture Case in PHP (MUZIK Online)Yi-Feng Tzeng
5.9K views116 slides
Hexagonal architecture message-oriented software design by
Hexagonal architecture   message-oriented software designHexagonal architecture   message-oriented software design
Hexagonal architecture message-oriented software designMatthias Noback
4.2K views76 slides
Holistic approach to machine learning by
Holistic approach to machine learningHolistic approach to machine learning
Holistic approach to machine learningSource Ministry
1.3K views78 slides
Machine learning for developers by
Machine learning for developersMachine learning for developers
Machine learning for developersSource Ministry
1.3K views83 slides
MySQL under the siege by
MySQL under the siegeMySQL under the siege
MySQL under the siegeSource Ministry
3.3K views94 slides

Viewers also liked(20)

Zephir - A Wind of Change for writing PHP extensions by Mark Baker
Zephir - A Wind of Change for writing PHP extensionsZephir - A Wind of Change for writing PHP extensions
Zephir - A Wind of Change for writing PHP extensions
Mark Baker2.1K views
Enterprise Architecture Case in PHP (MUZIK Online) by Yi-Feng Tzeng
Enterprise Architecture Case in PHP (MUZIK Online)Enterprise Architecture Case in PHP (MUZIK Online)
Enterprise Architecture Case in PHP (MUZIK Online)
Yi-Feng Tzeng5.9K views
Hexagonal architecture message-oriented software design by Matthias Noback
Hexagonal architecture   message-oriented software designHexagonal architecture   message-oriented software design
Hexagonal architecture message-oriented software design
Matthias Noback4.2K views
Holistic approach to machine learning by Source Ministry
Holistic approach to machine learningHolistic approach to machine learning
Holistic approach to machine learning
Source Ministry1.3K views
Machine learning for developers by Source Ministry
Machine learning for developersMachine learning for developers
Machine learning for developers
Source Ministry1.3K views
The top 10 things that any pro PHP developer should be doing by Kacper Gunia
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
Kacper Gunia944 views
Embrace Events and let CRUD die by Kacper Gunia
Embrace Events and let CRUD dieEmbrace Events and let CRUD die
Embrace Events and let CRUD die
Kacper Gunia697 views
Service discovery and configuration provisioning by Source Ministry
Service discovery and configuration provisioningService discovery and configuration provisioning
Service discovery and configuration provisioning
Source Ministry1.7K views
PHP7 - Scalar Type Hints & Return Types by Eric Poe
PHP7 - Scalar Type Hints & Return TypesPHP7 - Scalar Type Hints & Return Types
PHP7 - Scalar Type Hints & Return Types
Eric Poe3.5K views
Kreishäuser in Siegen by siwiarchiv
Kreishäuser in SiegenKreishäuser in Siegen
Kreishäuser in Siegen
siwiarchiv3.1K views
Ba z cityformu by froloo
Ba z cityformuBa z cityformu
Ba z cityformu
froloo834 views
Hiperion Digital Microwave Radio Presentation by Barry Rule
Hiperion Digital Microwave Radio PresentationHiperion Digital Microwave Radio Presentation
Hiperion Digital Microwave Radio Presentation
Barry Rule670 views
Reflexiones junto a la fuente taza, finales de octubre 2013 by gamiruela
Reflexiones junto a la fuente taza, finales de octubre 2013Reflexiones junto a la fuente taza, finales de octubre 2013
Reflexiones junto a la fuente taza, finales de octubre 2013
gamiruela10.4K views
Jayakar, pupul krishnamurti. biografía by sergi75
Jayakar, pupul   krishnamurti. biografíaJayakar, pupul   krishnamurti. biografía
Jayakar, pupul krishnamurti. biografía
sergi752.2K views
Enhancing the gas barrier properties of polylactic acid by means of electrosp... by Sergio Torres-Giner
Enhancing the gas barrier properties of polylactic acid by means of electrosp...Enhancing the gas barrier properties of polylactic acid by means of electrosp...
Enhancing the gas barrier properties of polylactic acid by means of electrosp...
Sergio Torres-Giner1.1K views
Mi vce 2000 ss & vce-2200 ss - Servicio Tecnico Fagor by serviciotecnicofagor
Mi vce 2000 ss & vce-2200 ss - Servicio Tecnico FagorMi vce 2000 ss & vce-2200 ss - Servicio Tecnico Fagor
Mi vce 2000 ss & vce-2200 ss - Servicio Tecnico Fagor

Similar to The IoC Hydra

Symfony2 from the Trenches by
Symfony2 from the TrenchesSymfony2 from the Trenches
Symfony2 from the TrenchesJonathan Wage
5.4K views40 slides
Singletons in PHP - Why they are bad and how you can eliminate them from your... by
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
43.5K views53 slides
Symfony2 - from the trenches by
Symfony2 - from the trenchesSymfony2 - from the trenches
Symfony2 - from the trenchesLukas Smith
3.3K views43 slides
Dependency injection in Drupal 8 by
Dependency injection in Drupal 8Dependency injection in Drupal 8
Dependency injection in Drupal 8Alexei Gorobets
3.8K views57 slides
PHP: 4 Design Patterns to Make Better Code by
PHP: 4 Design Patterns to Make Better CodePHP: 4 Design Patterns to Make Better Code
PHP: 4 Design Patterns to Make Better CodeSWIFTotter Solutions
1.2K views104 slides
Doctrine For Beginners by
Doctrine For BeginnersDoctrine For Beginners
Doctrine For BeginnersJonathan Wage
1.5K views69 slides

Similar to The IoC Hydra(20)

Symfony2 from the Trenches by Jonathan Wage
Symfony2 from the TrenchesSymfony2 from the Trenches
Symfony2 from the Trenches
Jonathan Wage5.4K views
Singletons in PHP - Why they are bad and how you can eliminate them from your... by go_oh
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_oh43.5K views
Symfony2 - from the trenches by Lukas Smith
Symfony2 - from the trenchesSymfony2 - from the trenches
Symfony2 - from the trenches
Lukas Smith3.3K views
Dependency injection in Drupal 8 by Alexei Gorobets
Dependency injection in Drupal 8Dependency injection in Drupal 8
Dependency injection in Drupal 8
Alexei Gorobets3.8K views
Doctrine For Beginners by Jonathan Wage
Doctrine For BeginnersDoctrine For Beginners
Doctrine For Beginners
Jonathan Wage1.5K views
Inversion Of Control by Chad Hietala
Inversion Of ControlInversion Of Control
Inversion Of Control
Chad Hietala1.2K views
Modularity and Layered Data Model by Attila Jenei
Modularity and Layered Data ModelModularity and Layered Data Model
Modularity and Layered Data Model
Attila Jenei1K views
How Kris Writes Symfony Apps by Kris Wallsmith
How Kris Writes Symfony AppsHow Kris Writes Symfony Apps
How Kris Writes Symfony Apps
Kris Wallsmith17.1K views
Phpne august-2012-symfony-components-friends by Michael Peacock
Phpne august-2012-symfony-components-friendsPhpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friends
Michael Peacock2.8K views
Domain Driven Design using Laravel by wajrcs
Domain Driven Design using LaravelDomain Driven Design using Laravel
Domain Driven Design using Laravel
wajrcs18.5K views
Decouple Your Code For Reusability (International PHP Conference / IPC 2008) by Fabien Potencier
Decouple Your Code For Reusability (International PHP Conference / IPC 2008)Decouple Your Code For Reusability (International PHP Conference / IPC 2008)
Decouple Your Code For Reusability (International PHP Conference / IPC 2008)
Fabien Potencier4.2K views
ZF2 for the ZF1 Developer by Gary Hockin
ZF2 for the ZF1 DeveloperZF2 for the ZF1 Developer
ZF2 for the ZF1 Developer
Gary Hockin3.3K views
What's New In Laravel 5 by Darren Craig
What's New In Laravel 5What's New In Laravel 5
What's New In Laravel 5
Darren Craig2.2K views
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I... by ZFConf Conference
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 Conference1.7K views
Lithium: The Framework for People Who Hate Frameworks by Nate Abele
Lithium: The Framework for People Who Hate FrameworksLithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate Frameworks
Nate Abele12.2K views
Build powerfull and smart web applications with Symfony2 by Hugo Hamon
Build powerfull and smart web applications with Symfony2Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2
Hugo Hamon6.4K views
Symfony components in the wild, PHPNW12 by Jakub Zalas
Symfony components in the wild, PHPNW12Symfony components in the wild, PHPNW12
Symfony components in the wild, PHPNW12
Jakub Zalas2.4K views
Symfony War Stories by Jakub Zalas
Symfony War StoriesSymfony War Stories
Symfony War Stories
Jakub Zalas6.3K views

More from Kacper Gunia

How a large corporation used Domain-Driven Design to replace a loyalty system by
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
867 views49 slides
Rebuilding Legacy Apps with Domain-Driven Design - Lessons learned by
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
2.9K views27 slides
Domain-driven Design in PHP and Symfony - Drupal Camp Wroclaw! by
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
6.5K views86 slides
OmniFocus - the #1 ‘Getting Things Done’ tool by
OmniFocus - the #1 ‘Getting Things Done’ toolOmniFocus - the #1 ‘Getting Things Done’ tool
OmniFocus - the #1 ‘Getting Things Done’ toolKacper Gunia
1.4K views45 slides
Code Dojo by
Code DojoCode Dojo
Code DojoKacper Gunia
2.9K views35 slides
SpecBDD in PHP by
SpecBDD in PHPSpecBDD in PHP
SpecBDD in PHPKacper Gunia
18.9K views51 slides

More from Kacper Gunia(6)

How a large corporation used Domain-Driven Design to replace a loyalty system by Kacper Gunia
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
Kacper Gunia867 views
Rebuilding Legacy Apps with Domain-Driven Design - Lessons learned by Kacper Gunia
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
Kacper Gunia2.9K views
Domain-driven Design in PHP and Symfony - Drupal Camp Wroclaw! by Kacper 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!
Kacper Gunia6.5K views
OmniFocus - the #1 ‘Getting Things Done’ tool by Kacper Gunia
OmniFocus - the #1 ‘Getting Things Done’ toolOmniFocus - the #1 ‘Getting Things Done’ tool
OmniFocus - the #1 ‘Getting Things Done’ tool
Kacper Gunia1.4K views
SpecBDD in PHP by Kacper Gunia
SpecBDD in PHPSpecBDD in PHP
SpecBDD in PHP
Kacper Gunia18.9K views

Recently uploaded

Dynamics of Hard-Magnetic Soft Materials by
Dynamics of Hard-Magnetic Soft MaterialsDynamics of Hard-Magnetic Soft Materials
Dynamics of Hard-Magnetic Soft MaterialsShivendra Nandan
13 views32 slides
SPICE PARK DEC2023 (6,625 SPICE Models) by
SPICE PARK DEC2023 (6,625 SPICE Models) SPICE PARK DEC2023 (6,625 SPICE Models)
SPICE PARK DEC2023 (6,625 SPICE Models) Tsuyoshi Horigome
15 views218 slides
Codes and Conventions.pptx by
Codes and Conventions.pptxCodes and Conventions.pptx
Codes and Conventions.pptxIsabellaGraceAnkers
7 views5 slides
SUMIT SQL PROJECT SUPERSTORE 1.pptx by
SUMIT SQL PROJECT SUPERSTORE 1.pptxSUMIT SQL PROJECT SUPERSTORE 1.pptx
SUMIT SQL PROJECT SUPERSTORE 1.pptxSumit Jadhav
11 views26 slides
What is Whirling Hygrometer.pdf by
What is Whirling Hygrometer.pdfWhat is Whirling Hygrometer.pdf
What is Whirling Hygrometer.pdfIIT KHARAGPUR
11 views3 slides
MK__Cert.pdf by
MK__Cert.pdfMK__Cert.pdf
MK__Cert.pdfHassan Khan
8 views1 slide

Recently uploaded(20)

Dynamics of Hard-Magnetic Soft Materials by Shivendra Nandan
Dynamics of Hard-Magnetic Soft MaterialsDynamics of Hard-Magnetic Soft Materials
Dynamics of Hard-Magnetic Soft Materials
Shivendra Nandan13 views
SUMIT SQL PROJECT SUPERSTORE 1.pptx by Sumit Jadhav
SUMIT SQL PROJECT SUPERSTORE 1.pptxSUMIT SQL PROJECT SUPERSTORE 1.pptx
SUMIT SQL PROJECT SUPERSTORE 1.pptx
Sumit Jadhav 11 views
What is Whirling Hygrometer.pdf by IIT KHARAGPUR
What is Whirling Hygrometer.pdfWhat is Whirling Hygrometer.pdf
What is Whirling Hygrometer.pdf
IIT KHARAGPUR 11 views
MSA Website Slideshow (16).pdf by msaucla
MSA Website Slideshow (16).pdfMSA Website Slideshow (16).pdf
MSA Website Slideshow (16).pdf
msaucla46 views
STUDY OF SMART MATERIALS USED IN CONSTRUCTION-1.pptx by AnnieRachelJohn
STUDY OF SMART MATERIALS USED IN CONSTRUCTION-1.pptxSTUDY OF SMART MATERIALS USED IN CONSTRUCTION-1.pptx
STUDY OF SMART MATERIALS USED IN CONSTRUCTION-1.pptx
AnnieRachelJohn31 views
Informed search algorithms.pptx by Dr.Shweta
Informed search algorithms.pptxInformed search algorithms.pptx
Informed search algorithms.pptx
Dr.Shweta13 views
Machine Element II Course outline.pdf by odatadese1
Machine Element II Course outline.pdfMachine Element II Course outline.pdf
Machine Element II Course outline.pdf
odatadese17 views
How I learned to stop worrying and love the dark silicon apocalypse.pdf by Tomasz Kowalczewski
How I learned to stop worrying and love the dark silicon apocalypse.pdfHow I learned to stop worrying and love the dark silicon apocalypse.pdf
How I learned to stop worrying and love the dark silicon apocalypse.pdf
An approach of ontology and knowledge base for railway maintenance by IJECEIAES
An approach of ontology and knowledge base for railway maintenanceAn approach of ontology and knowledge base for railway maintenance
An approach of ontology and knowledge base for railway maintenance
IJECEIAES12 views
Design and analysis of a new undergraduate Computer Engineering degree – a me... by WaelBadawy6
Design and analysis of a new undergraduate Computer Engineering degree – a me...Design and analysis of a new undergraduate Computer Engineering degree – a me...
Design and analysis of a new undergraduate Computer Engineering degree – a me...
WaelBadawy653 views

The IoC Hydra

  • 2. Kacper Gunia @cakper Technical Team Leader @SensioLabsUK Symfony Certified Developer PHPers Silesia @PHPersPL
  • 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 interface Listener
 {
 public function handle(Event $event);
 }
 
 interface Event
 {
 
 }
  • 25. EXAMPLE WITH EVENTS class FileEvent implements Event
 {
 private $path;
 public function __construct($path)
 {
 $this->path = $path;
 }
 
 public function getPath()
 {
 return $this->path;
 }
 }
  • 26. EXAMPLE WITH EVENTS class FileEraseWasInitialised extends FileEvent
 {
 
 }
 
 class FileWasErased extends FileEvent
 {
 
 }
  • 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/Scopes/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
  • 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
  • 79. PRIVATE SERVICES • It’s only a hint for compiler • Minor performance gain (inlines instations) • 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 • Will be removed in Symfony 3.0
  • 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
  • 100. STATEFUL SERVICES • Fetch state explicitly on per need basis (RequestStack) • Use Prototype scope only if you have to…
  • 103. 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
  • 104. New Instances Stateful Service Z Stateful Service Z Stateful Service Z Stateless Service A USING PROTOTYPE SCOPE WITH STRICT = FALSE
  • 105. FORGET ABOUT SCOPES ANYWAY WILL BE REMOVED IN SYMFONY 3.0 USE SHARED=FALSE INSTEAD
  • 108. EXTENDING BASE CONTROLLER • Easy to use by newcomers / low learning curve • Limits inheritance • Encourages using DIC as Service Locator • Hard unit testing
  • 109. CONTAINER AWARE INTERFACE • Controller is still coupled to framework • Lack of convenience methods • Encourages using DIC as Service Locator • Testing is still hard
  • 110. 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
  • 111. NONE OF THE ABOVE OPTIONS WILL FORCE YOU TO WRITE GOOD/BAD CODE
  • 113. FEATURES • Implementation of Mediator pattern • Allows for many-to-many relationships between objects • Makes your projects extensible • Supports priorities/stopping event flow
  • 114. EVENT DISPATCHER • Can be (really) hard to debug • Priorities of events / managing event flow • Events can be mutable - indirect coupling • Hard to test
  • 115. 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
  • 116. 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
  • 117. Listener A Listener B Listener C DispatcherService INDIRECT COUPLING PROBLEM
  • 119. 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
  • 120. CHAPTER 4: THE END ;)
  • 122. BE EXPLICIT & DON’T RELY ON MAGIC
  • 123. Kacper Gunia @cakper Technical Team Leader @SensioLabsUK Symfony Certified Developer PHPers Silesia @PHPersPL Thanks! https://joind.in/14979
  • 124. 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