Slide 1

Slide 1 text

Dependency Injection with PHP @BastianHofmann Why this talk?

Slide 2

Slide 2 text

Have you seen code like this? a mess of spaghetti code without any understandable logic, hard to read.

Slide 3

Slide 3 text

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?

Slide 4

Slide 4 text

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)).

Slide 5

Slide 5 text

Object Oriented Design on way to prevent this is ...

Slide 6

Slide 6 text

Dependency Inversion and one part of that that I want to focus on in this talk is dependency inversion

Slide 7

Slide 7 text

Dependency Injection which can be done by dependency injection

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

before that, a few words about me, I work at ResearchGate, the social network for researchers and scientists

Slide 10

Slide 10 text

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...

Slide 11

Slide 11 text

over 2.5 million users

Slide 12

Slide 12 text

here some impressions of the page

Slide 13

Slide 13 text

we are hiring, talk to me if you want

Slide 14

Slide 14 text

.. to have this in the company you are working for, and additionally want to work on some very interesting stuff

Slide 15

Slide 15 text

in addition to this i also speak frequently on conferences throughout the world

Slide 16

Slide 16 text

work and live in berlin

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

http://speakerdeck.com/u/bastianhofmann the slides with speaking notes will be available on speakerdeck after the talk

Slide 19

Slide 19 text

? what about you? php developers? own product/s or agency work? large codebases? who is using dependency injection containers already? which?

Slide 20

Slide 20 text

Dependency Inversion so let's start with ...

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

http://butunclebob.com/ ArticleS.UncleBob.PrinciplesOfOod or read this article by Robert C Martin (aka Uncle Bob)

Slide 24

Slide 24 text

http://www.doolwind.com/blog/solid-principles-for-game-developers/ so dependency inversion, what does that mean?

Slide 25

Slide 25 text

High-level modules should not depend on low level modules but on abstractions. ”

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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.

Slide 30

Slide 30 text

what does that mean in code?

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

Dependency Injection how to get rid of dependencies: by injecting them that is possible in different ways

Slide 33

Slide 33 text

Constructor

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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)

Slide 36

Slide 36 text

Setter

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

Method argument

Slide 39

Slide 39 text

or we can use method arguments to inject dependencies

Slide 40

Slide 40 text

Constructing classes

Slide 41

Slide 41 text

if we go with constructor injection, constructing a class may look like this

Slide 42

Slide 42 text

Benefits

Slide 43

Slide 43 text

nicer, more maintainable design

Slide 44

Slide 44 text

Easier to change that is easier to change with different implementations or during refactoring

Slide 45

Slide 45 text

Easier testing it is also easier to test because we can mock the dependencies

Slide 46

Slide 46 text

Only test the class, not the dependencies so we can only test our class and not all the dependencies with it

Slide 47

Slide 47 text

No content

Slide 48

Slide 48 text

No content

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

But...

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

Make it easier with factories so we can ...

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

nowadays there are multiple dependency injection containers out there, that work quite different

Slide 56

Slide 56 text

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.

Slide 57

Slide 57 text

https://github.com/researchgate/injektor of course its open source, you can check it out on github (pull requests very welcome)

Slide 58

Slide 58 text

http://getcomposer.org/ http://packagist.org/ and install it through composer

Slide 59

Slide 59 text

$ cat composer.json

Slide 60

Slide 60 text

$ 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

Slide 61

Slide 61 text

No content

Slide 62

Slide 62 text

Creating an instance of a class this is how it works

Slide 63

Slide 63 text

No content

Slide 64

Slide 64 text

that's how you get an instance of a class then, but what is that $CLASS?

Slide 65

Slide 65 text

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

Slide 66

Slide 66 text

PHP 5.5 by the way in php 5.5 this will be built in like this

Slide 67

Slide 67 text

Automatic creation of dependencies through Typehints

Slide 68

Slide 68 text

but this will still lead to an exception

Slide 69

Slide 69 text

@inject rg\injection needs an annotation so that it tries to create all dependencies automatically

Slide 70

Slide 70 text

technically not really necessary but good for clarity, so that you know that this classes dependencies are possibly injected automatically

Slide 71

Slide 71 text

What classes can be injected? or built with dic

Slide 72

Slide 72 text

No constructor

Slide 73

Slide 73 text

No content

Slide 74

Slide 74 text

Constructor without arguments

Slide 75

Slide 75 text

No content

Slide 76

Slide 76 text

Constructor with arguments that have default values

Slide 77

Slide 77 text

No content

Slide 78

Slide 78 text

Injectable constructor

Slide 79

Slide 79 text

No content

Slide 80

Slide 80 text

of course you can combine that

Slide 81

Slide 81 text

By the way: Property Injection

Slide 82

Slide 82 text

No content

Slide 83

Slide 83 text

Singletons with public static getInstance method following the same rules and protected constructor

Slide 84

Slide 84 text

No content

Slide 85

Slide 85 text

STOP: Don‘t use Singeltons

Slide 86

Slide 86 text

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

Slide 87

Slide 87 text

Let the DIC take care of instances

Slide 88

Slide 88 text

@singleton

Slide 89

Slide 89 text

PUBLIC Constructor

Slide 90

Slide 90 text

Passing additional, fixed values to instance

Slide 91

Slide 91 text

actually MUST here

Slide 92

Slide 92 text

Working with Interfaces

Slide 93

Slide 93 text

No content

Slide 94

Slide 94 text

But we can not create an instance of an Interface!

Slide 95

Slide 95 text

@implementedBy

Slide 96

Slide 96 text

No content

Slide 97

Slide 97 text

Named @implementedBy

Slide 98

Slide 98 text

No content

Slide 99

Slide 99 text

No content

Slide 100

Slide 100 text

Providers

Slide 101

Slide 101 text

@providedBy

Slide 102

Slide 102 text

No content

Slide 103

Slide 103 text

No content

Slide 104

Slide 104 text

Method invocation at DIC

Slide 105

Slide 105 text

No content

Slide 106

Slide 106 text

Same rules

Slide 107

Slide 107 text

No content

Slide 108

Slide 108 text

No content

Slide 109

Slide 109 text

And if you don‘t like annotations... ... or want to integrate 3rd party code

Slide 110

Slide 110 text

No content

Slide 111

Slide 111 text

No content

Slide 112

Slide 112 text

Great! So, how does it work?

Slide 113

Slide 113 text

Development: Reflection

Slide 114

Slide 114 text

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

Slide 115

Slide 115 text

No content

Slide 116

Slide 116 text

No content

Slide 117

Slide 117 text

No content

Slide 118

Slide 118 text

https://github.com/symfony/DependencyInjection

Slide 119

Slide 119 text

No content

Slide 120

Slide 120 text

No content

Slide 121

Slide 121 text

No content

Slide 122

Slide 122 text

No content

Slide 123

Slide 123 text

https://github.com/zendframework/zf2

Slide 124

Slide 124 text

No content

Slide 125

Slide 125 text

No content

Slide 126

Slide 126 text

Automatic creation of dependencies through Typehints

Slide 127

Slide 127 text

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

Slide 128

Slide 128 text

DEMO

Slide 129

Slide 129 text

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/ [email protected] 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.