The IoC Hydra
Click here to load reader
-
Upload
kacper-gunia -
Category
Engineering
-
view
2.178 -
download
0
Transcript of The IoC Hydra
![Page 1: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/1.jpg)
The IoC Hydra
![Page 2: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/2.jpg)
Kacper Gunia @cakper Technical Team Leader @SensioLabsUK
Symfony Certified Developer
PHPers Silesia @PHPersPL
![Page 3: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/3.jpg)
CHAPTER 1: THE THEORY
![Page 4: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/4.jpg)
THIS IS NOT YET ANOTHER DEPENDENCY INJECTION TALK ;)
![Page 5: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/5.jpg)
SO WE NEED SOME CLARIFICATION
![Page 6: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/6.jpg)
IOC !== DI
![Page 7: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/7.jpg)
–Pico Container
“Inversion of Control (IoC) is a design pattern that addresses a component’s dependency
resolution, configuration and lifecycle. ”
![Page 8: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/8.jpg)
–Pico Container
“It suggests that the control of those three should not be the concern of the component
itself. Thus it is inverted back.”
![Page 9: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/9.jpg)
–Pico Container
“Dependency Injection is where components are given their dependencies through their
constructors, methods, or directly into fields.”
![Page 10: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/10.jpg)
Inversion of Control
Dependency Injection
Events
AOP
![Page 11: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/11.jpg)
WHY DO WE IOC?
![Page 12: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/12.jpg)
PROS• Separation of concerns:
• dependency resolution, configuration and lifecycle
• Enforcing Single Responsibility Principle
• Easier testing
• Modular architecture, loose coupling
![Page 13: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/13.jpg)
CONS
• Learning curve
• Code is harder do analyse/debug
• Moves complexity somewhere else (doesn’t remove)
• Need for extra tools like Containers / Dispatchers
![Page 14: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/14.jpg)
HOW DO WE WRITE SOFTWARE WITHOUT IOC?
![Page 15: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/15.jpg)
EXAMPLE
interface FileEraser{ public function erase($filename); }
![Page 16: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/16.jpg)
EXAMPLEinterface Logger{ public function log($log); } class PrintingLogger implements Logger{ public function log($log) { echo $log; } }
![Page 17: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/17.jpg)
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.”); } }
![Page 18: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/18.jpg)
EXAMPLE
$eraser = new LocalFileEraser(); $eraser->erase('important-passwords.txt');
![Page 19: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/19.jpg)
HOW CAN WE FIX IT WITH DI?
![Page 20: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/20.jpg)
EXAMPLE WITH DIclass 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."); } }
![Page 21: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/21.jpg)
EXAMPLE WITH DI
$logger = new PrintingLogger(); $eraser = new LocalFileEraser($logger); $eraser->erase('important-passwords.txt');
![Page 22: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/22.jpg)
What (is being executed)Known Unknown
Kno
wn
Unkn
own
Whe
n (i
s be
ing
exec
uted
)
Dependency Injection
Stages of loosening control(from the component point of view)
![Page 23: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/23.jpg)
HOW CAN WE FIX IT WITH EVENTS?
![Page 24: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/24.jpg)
EXAMPLE WITH EVENTS
interface Listener{ public function handle(Event $event); } interface Event{ }
![Page 25: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/25.jpg)
EXAMPLE WITH EVENTSclass FileEvent implements Event{ private $path; public function __construct($path) { $this->path = $path; } public function getPath() { return $this->path; } }
![Page 26: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/26.jpg)
EXAMPLE WITH EVENTS
class FileEraseWasInitialised extends FileEvent{ } class FileWasErased extends FileEvent{ }
![Page 27: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/27.jpg)
EXAMPLE WITH EVENTSclass 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()); } }}
![Page 28: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/28.jpg)
EXAMPLE WITH EVENTStrait Observable{ private $listeners = []; public function addListener(Listener $listener) { $this->listeners[] = $listener; } public function dispatch(Event $event) { foreach ($this->listeners as $listener) { $listener->handle($event); } } }
![Page 29: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/29.jpg)
EXAMPLE WITH EVENTSclass LocalFileEraser implements FileEraser{ use Observable; public function erase($filename) { $this->dispatch(new FileEraseWasInitialised($filename)); unlink($filename); $this->dispatch(new FileWasErased($filename)); } }
![Page 30: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/30.jpg)
EXAMPLE WITH EVENTS
$eraser = new LocalFileEraser();
$listener = new LoggingFileEventListener(new PrintingLogger()); $eraser->addListener($listener); $eraser->erase('important-passwords.txt');
![Page 31: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/31.jpg)
What (is being executed)Known Unknown
Kno
wn
Unkn
own
Whe
n (i
s be
ing
exec
uted
)
Events
Stages of loosening control(from the component point of view)
![Page 32: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/32.jpg)
HOW CAN WE FIX IT WITH AOP?
![Page 33: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/33.jpg)
EXAMPLE WITH AOP USING DECORATOR
class LocalFileEraser implements FileEraser{ public function erase($filename) { unlink($filename); } }
![Page 34: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/34.jpg)
EXAMPLE WITH AOP USING DECORATORclass 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); } }
![Page 35: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/35.jpg)
EXAMPLE WITH AOP USING DECORATOR
$localFileEraser = new LocalFileEraser(); $logger = new PrintingLogger(); $eraser = new LoggingFileEraser($localFileEraser, $logger); $eraser->erase('important-passwords.txt');
![Page 36: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/36.jpg)
What (is being executed)Known Unknown
Kno
wn
Unkn
own
Whe
n (i
s be
ing
exec
uted
)
AOP
Stages of loosening control(from the component point of view)
![Page 37: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/37.jpg)
What (is being executed)Known Unknown
Kno
wn
Unkn
own
Whe
n (i
s be
ing
exec
uted
)
Dependency Injection Events
AOP
Stages of loosening control(from the component point of view)
![Page 38: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/38.jpg)
FRAMEWORKS & LIBRARIES
![Page 39: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/39.jpg)
A libraries provide functionality that you decide when to call.
![Page 40: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/40.jpg)
Frameworks provide an architecture for the application and
decide when to call your code.
![Page 41: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/41.jpg)
“DON’T CALL US, WE’LL CALL YOU”aka Hollywood Principle
![Page 42: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/42.jpg)
Frameworks utilise IoC principles and can be seen as one of its manifestations.
![Page 43: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/43.jpg)
CHAPTER 2: THE PRACTICE
![Page 44: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/44.jpg)
DEPENDENCY INJECTION CONTAINERS
![Page 45: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/45.jpg)
WHERE DIC CAN HELP
![Page 46: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/46.jpg)
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 \Monolog\Logger($loggerName); $stream = "app.log"; $logger->pushHandler(new \Monolog\Handler\StreamHandler($stream)); $controller = new RegistrationController($customerRepository, $mailer, $logger);
![Page 47: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/47.jpg)
RESOLVING GRAPHS OF OBJECTSuse Pimple\Container; $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']); };
![Page 48: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/48.jpg)
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']); };
![Page 49: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/49.jpg)
RESOLVING GRAPHS OF OBJECTS$container['logger_name'] = "App"; $container['stream_name'] = "app_" . $container['environment'] . ".log"; $container['logger'] = function ($c) { return new \Monolog\Logger($c['logger_name']); }; $container->extend('transport', function ($logger, $c) { $logger->pushHandler( new \Monolog\Handler\StreamHandler($c[‘stream_handler']) ); return $logger; }); $container['stream_handler'] = function ($c) { return new \Monolog\Handler\StreamHandler($c['stream_name']); };
![Page 50: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/50.jpg)
RESOLVING GRAPHS OF OBJECTS
$container['registration_controller'] = function ($c) { return new RegistrationController( $c['customer_repository'], $c['mailer'], $c[‘logger’] ); };
![Page 51: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/51.jpg)
LIFECYCLE MANAGEMENT
$container['session_storage'] = function ($c) { return new SessionStorage('SESSION_ID'); };
![Page 52: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/52.jpg)
LIFECYCLE MANAGEMENT
$container['session_storage'] = $container->factory(function ($c) { return new SessionStorage('SESSION_ID'); });
![Page 53: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/53.jpg)
WHERE DIC CAN HARM
![Page 54: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/54.jpg)
SERVICE LOCATOR
class RegistrationController { function resetPasswordAction() { $mailer = Container::instance()['mailer']; //... } }
![Page 55: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/55.jpg)
SERVICE LOCATOR• Coupled to container
• Responsible for resolving dependencies
• Dependencies are hidden
• Hard to test
• Might be ok when modernising legacy!
![Page 56: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/56.jpg)
SETTER INJECTION
![Page 57: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/57.jpg)
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
![Page 58: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/58.jpg)
SETTER INJECTIONclass 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"); } }}
![Page 59: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/59.jpg)
SETTER INJECTIONclass 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.”); } }
![Page 60: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/60.jpg)
SETTER INJECTION
class NullLogger implements Logger { public function log($log) { // whateva... } } $eraser = new LocalFileEraser(new NullLogger()); $eraser->erase('important-passwords.txt');
![Page 61: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/61.jpg)
PARTIAL APPLICATION
![Page 62: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/62.jpg)
DI WAY OF DOING THINGS
interface Logger{ public function log($log); } class PrintingLogger implements Logger{ public function log($log) { echo $log; } }
![Page 63: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/63.jpg)
DI WAY OF DOING THINGSclass 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"); } }
![Page 64: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/64.jpg)
DI WAY OF DOING THINGS
$logger = new PrintingLogger(); $eraser = new LocalFileEraser($logger); $eraser->erase('important-passwords.txt');
![Page 65: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/65.jpg)
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"); };
![Page 66: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/66.jpg)
FUNCTIONAL WAY OF DOING THINGS
use React\Partial; $erase = function (Logger $logger, $path) { $logger->log("Attempt to erase file: " . $path); unlink($path); $logger->log("File " . $path . " was deleted"); }; $erase = Partial\bind($erase, new PrintingLogger()); $erase('important-passwords.txt');
![Page 67: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/67.jpg)
CHAPTER 3: THE SYMFONY
![Page 68: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/68.jpg)
SYMFONY/DEPENDENCY-INJECTION
![Page 69: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/69.jpg)
FEATURES
• Many configurations formats
• Supports Factories/Configurators/Scopes/Decoration
• Extendable with Compiler Passes
• Supports lazy loading of services
![Page 70: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/70.jpg)
PERFORMANCE
![Page 71: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/71.jpg)
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
![Page 72: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/72.jpg)
LARGE NUMBER OF CONFIGURATION FILES
SLOWS CONTAINER BUILDER
![Page 73: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/73.jpg)
![Page 74: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/74.jpg)
SLOW COMPILATION
• Minimise number of bundles/config files used
• Try to avoid using extras like JMSDiExtraBundle
• Can be really painful on NFS
![Page 75: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/75.jpg)
LARGE CONTAINERS ARE SLOW TO LOAD
AND USE A LOT OF MEMORY
![Page 76: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/76.jpg)
LARGE CONTAINERS
• Review and remove unnecessary services/bundles etc.
• Split application into smaller ones with separate kernels
![Page 77: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/77.jpg)
PRIVATE SERVICES
![Page 78: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/78.jpg)
![Page 79: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/79.jpg)
PRIVATE SERVICES
• It’s only a hint for compiler
• Minor performance gain (inlines instations)
• Private services can still be fetched (not recommended)
![Page 80: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/80.jpg)
LAZY LOADING OF SERVICES
![Page 81: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/81.jpg)
LAZY LOADING OF SERVICES• Used when instantiation is expensive or not needed
• i.e. event listeners
• Solutions:
• Injecting container directly
• Using proxy objects
![Page 82: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/82.jpg)
INJECTING CONTAINER DIRECTLY
• As fast as it can be
• Couples service implementation to the container
• Makes testing harder
![Page 83: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/83.jpg)
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
![Page 84: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/84.jpg)
DEFINING CLASS NAMES AS PARAMETERS
![Page 85: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/85.jpg)
DEFINING CLASS NAMES AS PARAMETERS
• Rare use case (since decoration is supported even less)
• Adds overhead
• Will be removed in Symfony 3.0
![Page 86: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/86.jpg)
CIRCULAR REFERENCES
![Page 87: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/87.jpg)
![Page 88: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/88.jpg)
Security
Listener
Doctrine
CIRCULAR REFERENCE
![Page 89: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/89.jpg)
CIRCULAR REFERENCES
• Injecting Container is just a workaround
• Using setter injection after instantiation as well
• Solving design problem is the real challenge
![Page 90: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/90.jpg)
Doctrine
Security
Listener
TokenStorage
BROKEN CIRCULAR REFERENCE
![Page 91: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/91.jpg)
SCOPES
![Page 92: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/92.jpg)
MEANT TO SOLVE “THE REQUEST PROBLEM”
![Page 93: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/93.jpg)
SCOPE DEFINES STATE OF THE APPLICATION
![Page 94: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/94.jpg)
PROBLEMS WITH INJECTING REQUEST TO SERVICES
![Page 95: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/95.jpg)
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
![Page 96: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/96.jpg)
App
Controller A
Sub Request
Stateful service
Sub Request
Master Request
Stateful service
Master Request
Controller B
REQUESTS MANAGED WITH SCOPES
![Page 97: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/97.jpg)
App
Controller A
Stateless service
Request Stack
Controller B
SubRequest
MasterRequest
REQUESTS MANAGED WITH STACK
![Page 98: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/98.jpg)
STATEFUL SERVICES
![Page 99: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/99.jpg)
![Page 100: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/100.jpg)
STATEFUL SERVICES
• Fetch state explicitly on per need basis (RequestStack)
• Use Prototype scope only if you have to…
![Page 101: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/101.jpg)
PROTOTYPE SCOPE
![Page 102: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/102.jpg)
![Page 103: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/103.jpg)
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
![Page 104: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/104.jpg)
New Instances
StatefulService Z
StatefulService Z
StatefulService Z
Stateless Service A
USING PROTOTYPE SCOPE WITH STRICT = FALSE
![Page 105: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/105.jpg)
FORGET ABOUT SCOPES ANYWAY
WILL BE REMOVED IN SYMFONY 3.0
USE SHARED=FALSE INSTEAD
![Page 106: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/106.jpg)
CONTROLLERS
![Page 107: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/107.jpg)
![Page 108: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/108.jpg)
EXTENDING BASE CONTROLLER
• Easy to use by newcomers / low learning curve
• Limits inheritance
• Encourages using DIC as Service Locator
• Hard unit testing
![Page 109: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/109.jpg)
CONTAINER AWARE INTERFACE
• Controller is still coupled to framework
• Lack of convenience methods
• Encourages using DIC as Service Locator
• Testing is still hard
![Page 110: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/110.jpg)
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
![Page 111: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/111.jpg)
NONE OF THE ABOVE OPTIONS WILL FORCE YOU TO WRITE GOOD/BAD CODE
![Page 112: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/112.jpg)
SYMFONY/EVENT-DISPATCHER
![Page 113: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/113.jpg)
FEATURES
• Implementation of Mediator pattern
• Allows for many-to-many relationships between objects
• Makes your projects extensible
• Supports priorities/stopping event flow
![Page 114: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/114.jpg)
EVENT DISPATCHER
• Can be (really) hard to debug
• Priorities of events / managing event flow
• Events can be mutable - indirect coupling
• Hard to test
![Page 115: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/115.jpg)
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
![Page 116: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/116.jpg)
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
![Page 117: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/117.jpg)
Listener A
Listener B
Listener C
DispatcherService
INDIRECT COUPLING PROBLEM
![Page 118: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/118.jpg)
![Page 119: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/119.jpg)
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
![Page 120: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/120.jpg)
CHAPTER 4: THE END ;)
![Page 121: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/121.jpg)
BE PRAGMATIC
![Page 122: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/122.jpg)
BE EXPLICIT & DON’T RELY ON MAGIC
![Page 123: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/123.jpg)
Kacper Gunia @cakper Technical Team Leader @SensioLabsUK
Symfony Certified Developer
PHPers Silesia @PHPersPL
Thanks!https://joind.in/14979
![Page 124: The IoC Hydra](https://reader037.fdocuments.us/reader037/viewer/2022102322/58a2f25d1a28ab5d1c8b507d/html5/thumbnails/124.jpg)
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