Slide 1

Slide 1 text

DEPENDENCY INJECTION

Slide 2

Slide 2 text

DEPENDENCY INJECTION VS. SERVICE LOCATION DEPENDENCY INJECTION CONTAINERS Examples and Comparison PHP-DI Auryn FRAMEWORK INTEGRATION DEMO POPULAR FRAMEWORKS How they do it

Slide 3

Slide 3 text

SOLI [Dependency Inversion Principle] $coupling-- $reuse++

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

READABILITY ! TESTABILITY ! FLEXIBILITY ! MAINTAINABILITY

Slide 6

Slide 6 text

DEMO

Slide 7

Slide 7 text

Dependency Injection & DI Containers Service Locators ?

Slide 8

Slide 8 text

DEPENDENCY INJECTION

Slide 9

Slide 9 text

DEPENDENCY INJECTION MyService is now coupled to concrete DatabaseObject

Slide 10

Slide 10 text

DEPENDENCY INJECTION MyService is now coupled to concrete DatabaseObject MyService is now hard to test

Slide 11

Slide 11 text

DEPENDENCY INJECTION So, how else can we do it??

Slide 12

Slide 12 text

DEPENDENCY INJECTION Pass your object in via the constructor instead

Slide 13

Slide 13 text

DEPENDENCY INJECTION Code is now TESTABLE (eg. with phpunit) Object requirements can be seen from the method signatures only

Slide 14

Slide 14 text

POLYMORPHISM Dependency Injection Polymorphism Awesomeness

Slide 15

Slide 15 text

SERVICE LOCATION

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

SERVICE LOCATION One object to pass around (our "container") Access to any object, anywhere

Slide 18

Slide 18 text

SERVICE LOCATION Dependency Injection Here But Service Location Here

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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)

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

FRAMEWORKS Well known frameworks that (initially) used the SL pattern

Slide 23

Slide 23 text

SYMFONY 2 Service Locator Method dependencies unknown from signature

Slide 24

Slide 24 text

SYMFONY 2 Register dependencies Dependency Injection

Slide 25

Slide 25 text

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)

Slide 26

Slide 26 text

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)

Slide 27

Slide 27 text

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)

Slide 28

Slide 28 text

SILEX ServiceControllerServiceProvider Bootstrap: Define dependencies individually

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

DI CONTAINERS

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

AURYN INJECTOR A Dependency...

Slide 40

Slide 40 text

AURYN INJECTOR A Dependency... A service that needs the dependency... (Could be a controller)

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

Recursive Dependency Instantiation

Slide 44

Slide 44 text

POLYMORPHISM Typehint for an Interface instead

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

CONTROLLER RESOLVER DEMO

Slide 47

Slide 47 text

PHP-DI

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

READABILITY ! TESTABILITY ! FLEXIBILITY ! MAINTAINABILITY