Upgrade to Pro — share decks privately, control downloads, hide ads and more …

IoC container - CODEid Odessa 2018

IoC container - CODEid Odessa 2018

Did you know your IoC container can do a whole lot more than just constructor injection? Besides that it is actually packed with features. Inflectors, resolving callbacks, aliasing, method invocation to name a few. In this talk you will learn how to leverage the power of a great container and service providers to write better, loosely coupled code. Well designed code put together by your IoC container will make your applications SOLID, modular, lean and decoupled from the framework!

Hannes Van De Vreken

December 08, 2018
Tweet

More Decks by Hannes Van De Vreken

Other Decks in Technology

Transcript

  1. !

  2. WHAT IS IOC? $service = new Service(); $service->calculate(); $service =

    $container->get(Service::class); $service->calculate();
  3. WHAT IS IOC? class Service { public function __construct() {

    init(); } public function init() { $config = config(‘ftpsettings…’); $this->ftp = new FTP(…); } public function calculate() {…} }
  4. class Service { public function init() { // setup FTP

    } public function calculate() { // Get stuff from FTP. // Do calculations. // Return result. } } WHAT IS IOC?
  5. class Service { public function __construct(Ftp $ftp) { } public

    function calculate() { // Get stuff from FTP. // Do calculations. // Return result. } } WHAT IS IOC?
  6. class Service { public function __construct(Ftp $ftp) { } public

    function calculate() { // Get stuff from FTP. // Add caching to prevent hitting FTP over and over again // Do calculations. // Return result. } } WHAT IS IOC?
  7. class Service { public function __construct(Ftp $ftp) { } public

    function calculate() { // Get stuff from FTP. // Add caching to prevent hitting FTP over and over again // Log that FTP is accessed. // Do calculations. // Return result. } } WHAT IS IOC?
  8. class Service { public function __construct(Ftp $ftp) { } public

    function calculate() { // Get stuff from FTP. // Add caching to prevent hitting FTP over and over again // Log that FTP is accessed. // Do calculations. // Return result. } } WHAT IS IOC?
  9. class FtpStorage { public function __construct(Ftp $ftp) { $this->ftp =

    $ftp; } public function get($filename) { // Get it. // Cache it. // Log it. // Return it. } } WHAT IS IOC?
  10. class Service { public function __construct(FtpStorage $storage) {
 $this->storage =

    $storage; } public function calculate() { $value = $this->storage->get($key); // Do calculations. // Return result. } } WHAT IS IOC?
  11. class FtpStorage implements Storage { public function __construct(Ftp $ftp) {

    $this->ftp = $ftp; } public function get($filename) { … } } WHAT IS IOC?
  12. class Service { public function __construct(FtpStorage $storage) {
 $this->storage =

    $storage; } public function calculate() { $value = $this->storage->get($key); // Do calculations. // Return result. } } WHAT IS IOC?
  13. class Service { public function __construct(Storage $storage) {
 $this->storage =

    $storage; } public function calculate() { $value = $this->storage->get($key); // Do calculations. // Return result. } } WHAT IS IOC?
  14. class FtpStorage { public function __construct(Ftp $ftp) { $this->ftp =

    $ftp; } public function get($filename) { // Get it. // Cache it. // Log it. // Return it. } } WHAT IS IOC?
  15. class CacheDecorator implements Storage { public function __construct(Cache $cache, Storage

    $wrapped) {…} public function get($key) { return $this->cache->remember($key, 60, function () { return $this->wrapped->get($key); }); } } WHAT IS IOC?
  16. class LogDecorator implements Storage { public function __construct(LoggerInterface $log, Storage

    $wrapped) {…} public function get($key) { $this->log->info('Retrieved value for '.$key); return $this->wrapped->get($key); } } WHAT IS IOC?
  17. class FtpStorage { public function __construct(Ftp $ftp) { $this->ftp =

    $ftp; } public function get($filename) { // Get it. // Cache it. // Log it. // Return it. } } WHAT IS IOC?
  18. class FtpStorage { public function __construct(Ftp $ftp) { $this->ftp =

    $ftp; } public function get($filename) { // Get it. // Return it. } } WHAT IS IOC?
  19. WHAT IS IOC? FtpStorage implements <interface> Storage Service depends on

    depends on Ftp FtpStorage ervice depends on depends on Ftp
  20. $service = new Service( new CacheDecorator( $cache, new LogDecorator( $logger,

    new FtpStorage( new Ftp($settings) ) ) ) ); WHAT IS IOC?
  21. $container->get(Service::class); 1) Make FtpStorage 2) Wrap it with LogDecorator 3)

    Wrap LogDecorator instance with CacheDecorator 4) New up Service with CacheDecorator instance. WHAT IS IOC?
  22. Dependency inversion: Interface + implementation Dependency injection: Injecting `Storage` into

    `Service` Inversion of Control: The container builds your objects and calls them WHAT IS IOC?
  23. class SendInvoice { public function __construct(Mailer $mailer) { $this->mailer =

    $mailer; } public function listen(InvoiceGeneratedEvent $event) { … } } CONSTRUCTOR INJECTION
  24. But what if our code depends on interfaces… The container

    can’t construct interfaces? CONSTRUCTOR INJECTION
  25. class Mailer { /** * @param string $username * @param

    string $password */ public function construct($username, $password) {…} } REGISTRATION - BINDING
  26. Situation 3: When <<class>> is type hinted, always return the

    exact same object. REGISTRATION - BINDING
  27. Example: Global state in a - Translator (user’s locale) -

    Entity Manager - Event dispatcher REGISTRATION - BINDING
  28. Situation 4: When different classes need a different object of

    the same interface. REGISTRATION - BINDING
  29. class PhotosController { public function __construct(FilesystemInterface $photos) { } }

    class FilesController { public function __construct(FilesystemInterface $files) { } } REGISTRATION - BINDING
  30. // The PHP League $container->add('fs.photos', …); $container->add(PhotosController::class, function ( $fs

    = $container->get('fs.photos'); return new PhotosController($fs); }); REGISTRATION - BINDING
  31. Example 2: interface EnvironmentAware { public function setEnv($env); } trait

    EnvironmentAware { public function setEnv($env) { $this->env = $env; } } REGISTRATION - CONTAINER EVENTS
  32. Also useful for: - Quickly injecting stuff - Injecting soft

    dependencies REGISTRATION - CONTAINER EVENTS
  33. Also useful for: - Quickly injecting stuff - Injecting soft

    dependencies REGISTRATION - CONTAINER EVENTS
  34. Also useful for: - Quickly injecting stuff - Injecting soft

    dependencies - Setting configurable values REGISTRATION - CONTAINER EVENTS
  35. REGISTRATION public function register() { // Bindings } public function

    boot() { // Macros, extensions, container events, … }
  36. // Laravel $container->bind(‘fs', function ($args) { // Use $args[0] to

    see what folder to use. }); $container->get('fs', [‘images’]); CALLING THE CONTAINER
  37. // Laravel $container->bind(‘fs', function ($args) { // Use $args[0] to

    see what folder to use. }); $container->get('fs', [‘images']); $container->bind('fs.images', function () { return $container->get('fs', ['images']); CALLING THE CONTAINER
  38. Preferably only in - Event Dispatchers - Router - Command

    Bus - Factories - … CALLING THE CONTAINER
  39. Environment aware injection // Laravel $container->bind(‘fs.photos’, function () { if

    (getenv(‘APP_ENV’) === ‘integration’) { // Fill in memory adapter // with integration testing files
 } else { // Normal connection to S3. } }); BONUS