Pro Yearly is on sale from $80 to $50! »

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.

E189f89d366442f943d49e00566b6d51?s=128

James Mallison

October 08, 2016
Tweet

Transcript

  1. A few quick words about me James Mallison @J7mbo

  2. @J7mbo

  3. Dependency Injection and Dependency Inversion in PHP @J7mbo

  4. OOP, DI, DiP, IoC, DIC, SOLID, WTF @J7mbo

  5. @J7mbo

  6. @J7mbo

  7. @J7mbo

  8. @J7mbo

  9. @J7mbo

  10. @J7mbo

  11. Object Instantiation Http Request DOM Search @J7mbo

  12. @J7mbo

  13. Please be True… @J7mbo

  14. @J7mbo

  15. Asking for objects to be passed in is Dependency Injection

    Calling Code @J7mbo
  16. Inversion of Control @J7mbo

  17. 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
  18. Calling getContents() will now return this HTML Passing in our

    $fakeClient @J7mbo Our actual code
  19. Dependency Injection provides Control and Loose Coupling Inversion of.. @J7mbo

  20. 1 year later… @J7mbo

  21. “High-level modules should not depend on low-level modules. Both should

    depend on abstractions” @J7mbo
  22. Inversion of Control Dependencies are given to your object on

    creation (via Dependency Injection) Dependency Inversion Depend on abstractions rather than concretes @J7mbo
  23. @J7mbo

  24. Now uses a ConferenceRepository Instead (DB) New 2017 version @J7mbo

  25. “Polymorphism is the provision of a single interface to entities

    of different types” @J7mbo
  26. 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
  27. @J7mbo

  28. 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
  29. Framework (Object Oriented) (hopefully) @J7mbo

  30. Dependency Injection Container (DiC) @J7mbo

  31. Get the Conference object here @J7mbo

  32. External requirements should be visible from an object’s constructor and

    method signatures @J7mbo
  33. 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
  34. @J7mbo

  35. @J7mbo

  36. @J7mbo

  37. Create the BulgariaPHP2016 object @J7mbo

  38. @J7mbo

  39. Problem - Interfaces We still can’t ask for an interface

    and adhere to DiP - we can only ask for concretes
  40. Encounter “Conference” Create “BulgariaPHP2016” Search interface-to-concrete mapping / ‘binding’

  41. @J7mbo

  42. Automatic Injection for concrete classes @J7mbo

  43. @J7mbo

  44. @J7mbo

  45. See ‘Conference’ Create ‘BulgariaPHP2016’ @J7mbo

  46. @J7mbo

  47. @J7mbo

  48. 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
  49. 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
  50. 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
  51. 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
  52. @J7mbo

  53. • 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
  54. Where next? AOP and PHP7’s Anonymous Classes @J7mbo

  55. ‘Decorate’ existing Controller Delegate controller method call,
 but add additional

    functionality (logging) @J7mbo
  56. @J7mbo

  57. @J7mbo

  58. @J7mbo

  59. Anonymous Class Logging for any method call here @J7mbo

  60. 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
  61. 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
  62. • The ‘gang of four book’ (GoF) • The Clean

    Coder (Robert C. Martin) • Post your code on CodeReview (and survive) @J7mbo
  63. @J7mbo Thanks https://joind.in/talk/648b2 @j7mbo (PHP6 jokes, oop, confs, software engineering)