Dependency Injection

Dependency Injection

A talk on Inversion of Control, Dependency Injection, Service Locators, Dependency Injection Containers and general awesomeness.

E189f89d366442f943d49e00566b6d51?s=128

James Mallison

March 04, 2014
Tweet

Transcript

  1. DEPENDENCY INJECTION

  2. DEPENDENCY INJECTION VS. SERVICE LOCATION DEPENDENCY INJECTION CONTAINERS Examples and

    Comparison PHP-DI Auryn FRAMEWORK INTEGRATION DEMO POPULAR FRAMEWORKS How they do it
  3. SOLI [Dependency Inversion Principle] $coupling-- $reuse++

  4. SOLI [Dependency Inversion Principle] $coupling-- $reuse++ SL DI

  5. READABILITY ! TESTABILITY ! FLEXIBILITY ! MAINTAINABILITY

  6. DEMO

  7. Dependency Injection & DI Containers Service Locators ?

  8. DEPENDENCY INJECTION

  9. DEPENDENCY INJECTION MyService is now coupled to concrete DatabaseObject

  10. DEPENDENCY INJECTION MyService is now coupled to concrete DatabaseObject MyService

    is now hard to test
  11. DEPENDENCY INJECTION So, how else can we do it??

  12. DEPENDENCY INJECTION Pass your object in via the constructor instead

  13. DEPENDENCY INJECTION Code is now TESTABLE (eg. with phpunit) Object

    requirements can be seen from the method signatures only
  14. POLYMORPHISM Dependency Injection Polymorphism Awesomeness

  15. SERVICE LOCATION

  16. SERVICE LOCATION One object to pass around (our "container")

  17. SERVICE LOCATION One object to pass around (our "container") Access

    to any object, anywhere
  18. SERVICE LOCATION Dependency Injection Here But Service Location Here

  19. SERVICE LOCATION Dependency Injection Here Actual dependencies still hidden from

    method signature (they're in this "container") MyService now tied to container But Service Location Here
  20. SERVICE LOCATION NOT A FACTORY Factories: build and return objects

    SLs: equivalent of an associative array Set objects at bootstrap Retrieve objects when requested Objects may be instantiated lazily (only when you ask for them, think via PHP 5's closures)
  21. WHY DI > SL Every object you create: • The

    public methods are an API to the object's usage • How the methods can be used should be visible from the method signatures alone Pass in your container = a container dependency, hard to test etc Pass in your object = we know exactly what the object needs to run
  22. FRAMEWORKS Well known frameworks that (initially) used the SL pattern

  23. SYMFONY 2 Service Locator Method dependencies unknown from signature

  24. SYMFONY 2 Register dependencies Dependency Injection

  25. SYMFONY 2 Complexity increases for other arguments, dependencies etc Injection

    in constructor, but may not be used by all methods (waste of resources for controllers)
  26. SILEX The whole app is a service locator... $foo contains:

    • Logging • Database • Other registered services • Let's go check the docs... (to the developer writing it)
  27. SILEX The whole app is a service locator... $foo contains:

    • Logging • Database • Other registered services • Let's go check the docs... (to the developer writing it) $foo contains: • No idea... • Let's go check the docs... (to a future developer)
  28. SILEX ServiceControllerServiceProvider Bootstrap: Define dependencies individually

  29. SILEX ServiceControllerServiceProvider Bootstrap: Define dependencies individually Bootstrap: Define controller with

    the above
  30. SILEX ServiceControllerServiceProvider Bootstrap: Define dependencies individually Bootstrap: Define controller with

    the above Controller: Typehint for your dependency
  31. SILEX ServiceControllerServiceProvider Bootstrap: Define dependencies individually Bootstrap: Define controller with

    the above Controller: Typehint for your dependency Great! But still a lot just for one dependency... Still constructor-only injection
  32. SO FAR... Popular frameworks offer both Dependency Injection and Service

    Location SL = simpler, but couples service to container DI = Testable code, but time consuming to set up and configure Method requirements should be visible from the method signature only Constructor-only injection in your controllers shares objects that may not need to be shared Note: we're not talking about setter injection here Method injection in your controllers provides a clear explanation of the method's needs Controllers don't always adhere to SRP anyway
  33. DEPENDENCY INJECTION Starts most visibly at the Controller Resolution level

    Look at the controller resolver to see where you can place a DI container
  34. DEPENDENCY INJECTION Starts most visibly at the Controller Resolution level

    Look at the controller resolver to see where you can place a DI container
  35. DEPENDENCY INJECTION Starts most visibly at the Controller Resolution level

    Look at the controller resolver to see where you can place a DI container
  36. DEPENDENCY INJECTION Starts most visibly at the Controller Resolution level

    Look at the controller resolver to see where you can place a DI container Decorate existing class to maintain default functionality
  37. DI CONTAINERS

  38. DI CONTAINERS Composition Root pattern Define your object graph ("wiring")

    as close to the top layer as possible ie. in your bootstrap In PHP, this could involve: Sequentially manually created objects An array of object mappings as strings A configuration file containing mappings
  39. AURYN INJECTOR A Dependency...

  40. AURYN INJECTOR A Dependency... A service that needs the dependency...

    (Could be a controller)
  41. AURYN INJECTOR Usage 1. Uses reflection to read the method

    signature of MyService 2. Sees the typehint for DatabaseObject 3. Uses reflection to read the method signature for DatabaseObject 4. No dependencies here, creates the DatabaseObject and injects it into MyService
  42. AURYN INJECTOR Usage 1. Uses reflection to read the method

    signature of MyService 2. Sees the typehint for DatabaseObject 3. Uses reflection to read the method signature for DatabaseObject 4. No dependencies here, creates the DatabaseObject and injects it into MyService Do this in your composition root Do this in your controller resolver
  43. Recursive Dependency Instantiation

  44. POLYMORPHISM Typehint for an Interface instead

  45. POLYMORPHISM Runtime Polymorphism via the DiC DatabaseInterface will use "MongoDbInstead"

    concrete class When "MyService" is resolved: 1. The constructor signature will be read via reflection 2. The DatabaseInterface will be found as a dependency 3. The alias for DatabaseInterface is "MongoDbInstead" 4. The MongoDbInstead class is dependency injected for us
  46. CONTROLLER RESOLVER DEMO

  47. PHP-DI

  48. PHP-DI VS AURYN PHP-DI AURYN Recursive DI and Caching Recursive

    DI and Caching Nice website, more in-depth docs Github-only, less support Constructor-only Injection Application-wide Injection
  49. READABILITY ! TESTABILITY ! FLEXIBILITY ! MAINTAINABILITY