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

Bulgaria PHP 2016 - Dependency Injection & Dependency Inversion in PHP

Bulgaria PHP 2016 - Dependency Injection & Dependency Inversion in PHP

Dependency Injection and Dependency Inversion are important tools for writing testable and reusable code. They are available in any object oriented language and PHP is no exception. In this talk we will look at both Dependency Injection and the Dependency Inversion Principle, how they fit in with SOLID, and why they should be used when writing object oriented code.

How are objects wired together? What is an object graph? Is a Dependency Injection Container the right way forward? Can we do this automatically, and are there any patterns or reusable components available to help us achieve reusable and decoupled code? These are some of the topics covered in this talk from both a theoretical and a practical standpoint.

Walking out of the room you should understand why dependency injection is so heavily advocated in programming and how you can use it to write awesome, decoupled code in PHP.

James Mallison

October 08, 2016
Tweet

More Decks by James Mallison

Other Decks in Technology

Transcript

  1. The old way Object finds the objects it needs for

    itself, then calls them. The new way Dependencies are handed to the object when created. Inversion of Control @J7mbo
  2. Inversion of Control Dependencies are given to your object on

    creation (via Dependency Injection) Dependency Inversion Depend on abstractions rather than concretes @J7mbo
  3. Recap • Dependency Injection is simply passing in object dependencies

    as parameters instead of instantiating them in the object using them • Doing this gives you Inversion of Control, as the control over object creation is no longer delegated to the object using them • Using interfaces, we can adhere to the Dependency Inversion Principle and depend on abstractions • Code always starts off procedural, and builds objects up before executing them in an object oriented manner • If you use don’t do this, other people will hate you because they can’t mock your objects easily in their tests (so your code is not testable) @J7mbo
  4. Bootstrap (Procedural) Framework (Object Oriented) (hopefully) Dev Code (Object Oriented)

    (hopefully) Composition Root Objects built Match route to controller + action Create controller object Run action (method) with any request parameters Developer creates a controller Does whatever they want @J7mbo
  5. Bootstrap (Procedural) Framework (Object Oriented) (hopefully) Dev Code (Object Oriented)

    (hopefully) Composition Root Objects defined and registed in container Match route to controller + action Container Creates controller (with dependencies) Container runs action with any request parameters Developer creates a controller DI’s registered dependencies Does whatever they want ‘Object Graph’ @J7mbo
  6. Problem - Interfaces We still can’t ask for an interface

    and adhere to DiP - we can only ask for concretes
  7. Bootstrap (Procedural) Framework (Object Oriented) (hopefully) Dev Code (Object Oriented)

    (hopefully) Composition Root Relationships (object graph) defined in configuration file Match route to controller + action Injector Creates controller (with dependencies) Developer creates a controller DI’s registered dependencies Does whatever they want • Not coupled to container • Remove code / move code about at any time • Concentrate on writing SOLID code @J7mbo
  8. Dev Code (Object Oriented) (hopefully) Developer creates a controller DI’s

    registered dependencies Does whatever they want • Not coupled to container • Remove code / move code about at any time • Concentrate on writing SOLID code @J7mbo
  9. Automatic Injection - Positives • Auto-injection for concretes, because we

    don’t interface everything • Auto-injection for interfaces that have a single concrete available (look through composer-loaded classes?) • Configured auto-injection through ‘aliasing’ or ‘binding’ a concrete to an interface • Edge cases - specifying instances for specific modules
  10. Automatic Injection - Negatives • Likely requires framework and infrastructure

    set up from the beginning of the project • Reflection is slow (but you can cache these like Composer’s optimised autoloader for production (-o)); Auryn caches
  11. • Your objects should specify external requirements needed in their

    constructor and method signatures • Dependency Injection is simply passing in external requirements as parameters • Using interfaces for functionality that might change provides polymorphism (switch out concrete implementation any time) • Depending on abstractions rather than concretes (interfaces), and having your object graph composed ‘higher’ in the codebase (composition root), provides Inversion of Control and helps you adhere to the Dependency Inversion Principle @J7mbo
  12. How can I apply this? • Choose a framework that

    supports automatic recursive DI • Choose a micro-framework or components that allow you to substitute the ‘controller resolver’ to provide this • Legacy codebase? Don’t have to use an auto-injector, just design your interfaces well adhere to DIP when you can • In your next project, make this a primary consideration of your software architecture @J7mbo
  13. Current Framework Solutions? @J7mbo • Symfony has autowire: true as

    of version 2.8+ • Other frameworks have it out-of-the-box • Micro-frameworks (like Silex) allow you to replace how the controller is instantiated ($app[controller.resolver]) and you can write the code to use an injector like Auryn
  14. • The ‘gang of four book’ (GoF) • The Clean

    Coder (Robert C. Martin) • Post your code on CodeReview (and survive) @J7mbo