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

Dependency Injection with PHP

Dependency Injection with PHP

Bastian Hofmann

February 28, 2013
Tweet

More Decks by Bastian Hofmann

Other Decks in Programming

Transcript

  1. Dependency Injection with PHP @BastianHofmann Why this talk?

  2. Have you seen code like this? a mess of spaghetti

    code without any understandable logic, hard to read.
  3. or like this? acient legacy code where nobody knows how

    it works anymore and what it even does, and you are afraid to touch it?
  4. in actual code this may probably look somehow like this,

    look sql queries, views, everything jubmled together in some weirdly named funtions (also really insecure (xss)).
  5. Object Oriented Design on way to prevent this is ...

  6. Dependency Inversion and one part of that that I want

    to focus on in this talk is dependency inversion
  7. Dependency Injection which can be done by dependency injection

  8. Dependency Injection Containers and made easier with dependency injection containers

    so that you avoid ending up such a code mess in your project or to help you when you have to refactor such a mess
  9. before that, a few words about me, I work at

    ResearchGate, the social network for researchers and scientists
  10. ResearchGate gives science back to the people who make it

    happen. We help researchers build reputation and accelerate scientific progress. On their terms. ‟ the goal is to give...
  11. over 2.5 million users

  12. here some impressions of the page

  13. we are hiring, talk to me if you want

  14. .. to have this in the company you are working

    for, and additionally want to work on some very interesting stuff
  15. in addition to this i also speak frequently on conferences

    throughout the world
  16. work and live in berlin

  17. Questions? Ask by the way, if you have any questions

    throughout this talk, if you don't understand something, just raise your hand and ask. probably my fault anyways since i spoke to quickly or my accent was too bad
  18. http://speakerdeck.com/u/bastianhofmann the slides with speaking notes will be available on

    speakerdeck after the talk
  19. ? what about you? php developers? own product/s or agency

    work? large codebases? who is using dependency injection containers already? which?
  20. Dependency Inversion so let's start with ...

  21. http://www.doolwind.com/blog/solid-principles-for-game-developers/ dependency inversion is one of the 5 principles of

    SOLID software design, SOLID means: single responsibility, open/closed principle, liskov substitution principle, interface segregation principle, dependency inversion principle
  22. http://qafoo.com/presentations.html I will only touch dependency inversion in this talk,

    if you want to know more about SOLID I recommend this excellent talk from Tobias Schlitt
  23. http://butunclebob.com/ ArticleS.UncleBob.PrinciplesOfOod or read this article by Robert C Martin

    (aka Uncle Bob)
  24. http://www.doolwind.com/blog/solid-principles-for-game-developers/ so dependency inversion, what does that mean?

  25. High-level modules should not depend on low level modules but

    on abstractions. ”
  26. A B C so you have a module a that

    depend on a module b that depends on a module c. pretty common dependency graph but actually a violation of the dependency inversion principle
  27. A B C interface interface instead a should depend on

    an interface which is in it's own module that is implemented by b, and b should depend on an interface that is implemented by c. so we are inverting the dependency chain
  28. A B C interface if you have two modules depending

    on the same sub-module, you could extract the common interface into its own module
  29. A B Adapter interface C and if c is actually

    3rd party or legacy code that you can't change, you could write an adapter class that implements the interface and extends c. this is actually very good practice because than you easily can change the implementation of c if you want to without touching your other code because the interface can stay the same.
  30. what does that mean in code?

  31. in this example class we have several hardcoded dependencies: Cache,

    Validator and HttpClient, actually also the json_decode call is somewhat a dependency. this makes our class hard to test, we can not mock the dependencies so for testing we actually need a test and an http service, also if we want to change the validator in our whole codebase, that would mean lot's of work
  32. Dependency Injection how to get rid of dependencies: by injecting

    them that is possible in different ways
  33. Constructor

  34. we can inject the dependencies through constructor arguments, easy to

    mock now, but we still depend on concrete implementations here, and not interfaces (abstractions), so still much work if we want to change an implementation
  35. better, lets just depend on interfaces, so if we want

    to change the implementation e.g. of the validator, the only thing we still have to make sure is to implement the same interface (for example through an adapter class)
  36. Setter

  37. you can also inject dependencies through a setter, good for

    optional dependencies. in this example we should then add a check if $this->cache is really set
  38. Method argument

  39. or we can use method arguments to inject dependencies

  40. Constructing classes

  41. if we go with constructor injection, constructing a class may

    look like this
  42. Benefits

  43. nicer, more maintainable design

  44. Easier to change that is easier to change with different

    implementations or during refactoring
  45. Easier testing it is also easier to test because we

    can mock the dependencies
  46. Only test the class, not the dependencies so we can

    only test our class and not all the dependencies with it
  47. None
  48. None
  49. http://www.doolwind.com/blog/solid-principles-for-game-developers/ also all this injection of dependencies makes it easier

    to comply with another of the solid principles called the single responsibility principle, which says that a class only does one thing and not multiple things. the multiple things we could then just refactor out of the class and inject them as dependencies
  50. But...

  51. this is not really nice, especially if we need this

    service in 500 different places in our codebase, adding a dependency afterwards would also be a refactoring nightmare
  52. Make it easier with factories so we can ...

  53. so instead of creating our service manually each time, we

    can just call this factory method which creates it for us, if we add or change a dependency this is then the only place where we have to add it
  54. Dependency Injection Container which directly leads us to dependency injection

    containers, because in the end the help us or automate the process of creating these factories
  55. nowadays there are multiple dependency injection containers out there, that

    work quite different
  56. rg\injektor inspired by google-guice i want to explain the workings

    of a dic on the container we wrote for researchgate and which is modeled after google-guice, a java dic. which of the dics you choose is mostly a matter of different requirements and taste. since all of them work a bit differently in usage, configuration and performance. one of our goals in writing our own was to make it very easy and unnoticable to use while still being very fast.
  57. https://github.com/researchgate/injektor of course its open source, you can check it

    out on github (pull requests very welcome)
  58. http://getcomposer.org/ http://packagist.org/ and install it through composer

  59. $ cat composer.json

  60. $ wget http://getcomposer.org/composer.phar $ php composer.phar install Installing dependencies -

    Installing monolog/monolog (1.1.0) Downloading: 100% ... monolog/monolog suggests installing mlehner/ gelf-php (Allow sending log messages to a GrayLog2 server) Writing lock file Generating autoload files
  61. None
  62. Creating an instance of a class this is how it

    works
  63. None
  64. that's how you get an instance of a class then,

    but what is that $CLASS?
  65. for convenience it is a good practice to add something

    like this public static property to a class which returns the class name of the class as a string, this gives you ide support like auto completion, usage analysis, refactoring support and so on
  66. PHP 5.5 by the way in php 5.5 this will

    be built in like this
  67. Automatic creation of dependencies through Typehints

  68. but this will still lead to an exception

  69. @inject rg\injection needs an annotation so that it tries to

    create all dependencies automatically
  70. technically not really necessary but good for clarity, so that

    you know that this classes dependencies are possibly injected automatically
  71. What classes can be injected? or built with dic

  72. No constructor

  73. None
  74. Constructor without arguments

  75. None
  76. Constructor with arguments that have default values

  77. None
  78. Injectable constructor

  79. None
  80. of course you can combine that

  81. By the way: Property Injection

  82. None
  83. Singletons with public static getInstance method following the same rules

    and protected constructor
  84. None
  85. STOP: Don‘t use Singeltons

  86. Singletons are evil! not sanely testable, mixture of responsibilites, you

    don‘t know about the state of the singleton at all, same as static functions
  87. Let the DIC take care of instances

  88. @singleton

  89. PUBLIC Constructor

  90. Passing additional, fixed values to instance

  91. actually MUST here

  92. Working with Interfaces

  93. None
  94. But we can not create an instance of an Interface!

  95. @implementedBy

  96. None
  97. Named @implementedBy

  98. None
  99. None
  100. Providers

  101. @providedBy

  102. None
  103. None
  104. Method invocation at DIC

  105. None
  106. Same rules

  107. None
  108. None
  109. And if you don‘t like annotations... ... or want to

    integrate 3rd party code
  110. None
  111. None
  112. Great! So, how does it work?

  113. Development: Reflection

  114. Production: Generated Factory Classes why that? normally DIC gets classname,

    reflection, looks at constructor arguments, injectable or not? if class start over recursively, but reflection is slow, so instead of reflection it uses factory classes that are pre generated during deployment like the factory classes we saw earlier
  115. None
  116. None
  117. None
  118. https://github.com/symfony/DependencyInjection

  119. None
  120. None
  121. None
  122. None
  123. https://github.com/zendframework/zf2

  124. None
  125. None
  126. Automatic creation of dependencies through Typehints

  127. https://github.com/bashofmann/dic_demo/

  128. DEMO

  129. http://twitter.com/BastianHofmann http://profiles.google.com/bashofmann http://lanyrd.com/people/BastianHofmann http://speakerdeck.com/u/bastianhofmann https://github.com/bashofmann https://www.researchgate.net/profile/Bastian_Hofmann/ mail@bastianhofmann.de Did you like

    this talk? https://joind.in/7880 thanks, you can contact me on any of these platforms or via mail. if you liked this talk or didn't like it, please rate it on joind.in. this is very important for me for improving my talk, for the organizers for selecting the best talks and speakers and for you to get the best content on the conferences you visit.