From 192a207e2db94a2050b025e168b4a729fef4a517 Mon Sep 17 00:00:00 2001 From: happyaccidents Date: Thu, 28 Nov 2013 12:17:44 +0000 Subject: [PATCH] First draft - Resolves #280 --- _posts/06-01-01-Dependency-Injection.md | 8 ++++ _posts/06-02-01-Basic-Concept.md | 57 +++++++++++++++++++++++++ _posts/06-03-01-Complex-Problem.md | 49 +++++++++++++++++++++ _posts/06-04-01-Containers.md | 14 ++++++ _posts/06-05-01-Further-Reading.md | 11 +++++ 5 files changed, 139 insertions(+) create mode 100644 _posts/06-01-01-Dependency-Injection.md create mode 100644 _posts/06-02-01-Basic-Concept.md create mode 100644 _posts/06-03-01-Complex-Problem.md create mode 100644 _posts/06-04-01-Containers.md create mode 100644 _posts/06-05-01-Further-Reading.md diff --git a/_posts/06-01-01-Dependency-Injection.md b/_posts/06-01-01-Dependency-Injection.md new file mode 100644 index 0000000..3bac06e --- /dev/null +++ b/_posts/06-01-01-Dependency-Injection.md @@ -0,0 +1,8 @@ +--- +title: Dependency Injection +--- + +# Dependency Injection {#dependency_injection_title} + +Dependency Injection is a basic concept that solves a complex problem. As a software design pattern it is being adopted in +some way or another by all major PHP projects. diff --git a/_posts/06-02-01-Basic-Concept.md b/_posts/06-02-01-Basic-Concept.md new file mode 100644 index 0000000..1748afe --- /dev/null +++ b/_posts/06-02-01-Basic-Concept.md @@ -0,0 +1,57 @@ +--- +isChild: true +--- + +## Basic Concept {#basic_concept_title} + +From [Wikipedia](http://en.wikipedia.org/wiki/Dependency_injection): + +> Dependency injection is a software design pattern that allows the removal of hard-coded dependencies and makes it +> possible to change them, whether at run-time or compile-time. + +This quote makes the concept sound much more complicated than it actually is. Dependency Injection is providing a component +with it's dependencies either through constructor injection, method calls or the setting of properties. It is that simple. + +We can demonstrate the concept with a simple, yet naive, example. + +{% highlight php %} +adapter = new MySqlAdapter; + } +} + +class MysqlAdapter {} +{% endhighlight %} + +Here we have a `Database` class that requires an adapter to speak to the database. We instantiate the +adapter in the constructor and create a hard dependency. This code can be refactored to use Dependency Injection +and therefore loosen the dependency. + +{% highlight php %} +adapter = $adapter; + } +} + +class MysqlAdapter {} +{% endhighlight %} + +Now we are giving the `Database` class it's dependency rather than it creating it itself. We could even create a method +that would accept an argument of the dependency and set it that way, or if the `$adapter` property was `public` we could +set it directly. diff --git a/_posts/06-03-01-Complex-Problem.md b/_posts/06-03-01-Complex-Problem.md new file mode 100644 index 0000000..07050d2 --- /dev/null +++ b/_posts/06-03-01-Complex-Problem.md @@ -0,0 +1,49 @@ +--- +isChild: true +--- + +## Complex Problem {#complex_problem_title} + +If you have ever read about Dependency Injection then you have probably seen the terms *"Inversion of Control"* or *"Dependency Inversion Principle"*. +These are the complex problems that Dependency Injection solves, or to be more precise, elegantly solves. + +For years, PHP frameworks have been achieving Inversion of Control, however, the question became, which part of control +are you inverting, and where to? For example, MVC frameworks would generally provide a super object or base controller that other +controllers must extend to gain access to it's dependencies. This **is** Inversion of Control, however, instead of loosening +dependencies, this method simply moved them. + +Dependency Injection allows us to more elegantly solve this problem by only injecting the dependencies we need, when we need them, +without the need for any hard coded dependencies at all. + +Dependency Inversion Principle is the "D" in the S.O.L.I.D set of object oriented design principles that states one should +*"Depend on Abstractions. Do not depend on concretions."*. Put simply, this means our dependencies should be interfaces/contracts or abstract +classes rather than concrete implementations. We can easily refactor the above example to follow this principle. + +{% highlight php %} +adapter = $adapter; + } +} + +interface AdapterInterface {} + +class MysqlAdapter implements AdapterInterface {} +{% endhighlight %} + +There are several benefits to the Database class now depending on an interface rather than a concretion. + +Consider that you are working in a team and the adapter is being worked on by a colleague. In our first example, we would have +to wait for said colleague to finish the adapter before we could properly mock it for our unit tests. Now that the dependency +is an interface/contract we can happily mock that interface knowing that our colleague will build the adapter based on that contract. + +An even bigger benefit to this method is that our code is now much more scalable. If a year down the line we decide that we +want to migrate to a different type of database, we can write an adapter that implements the original interface and inject that instead, +no more refactoring would be required as we can ensure that the adapter follows the contract set by the interface. diff --git a/_posts/06-04-01-Containers.md b/_posts/06-04-01-Containers.md new file mode 100644 index 0000000..b3eca74 --- /dev/null +++ b/_posts/06-04-01-Containers.md @@ -0,0 +1,14 @@ +--- +isChild: true +--- + +## Containers {#containers_title} + +The first thing you should understand about Dependency Injection Containers is that they are not the same thing as Dependency +Injection. A container is a convenience utility that helps us implement Dependency Injection, however, they can be and often +are misused to implement an anti pattern, Service Location. Using a container as a Service Locator within your classes arguably +creates a harder dependency on the container than the dependency you are replacing. It also makes your code much less transparent +and ultimately harder to test. + +Most modern frameworks have their own Dependency Injection Container that allows you to wire your dependencies together through configuration. +What this means in practice is that you can write application code that is as clean and de-coupled as the framework it is built on. diff --git a/_posts/06-05-01-Further-Reading.md b/_posts/06-05-01-Further-Reading.md new file mode 100644 index 0000000..e1d3645 --- /dev/null +++ b/_posts/06-05-01-Further-Reading.md @@ -0,0 +1,11 @@ +--- +isChild: true +--- + +## Further Reading {#further_reading_title} + +- [Learning about Dependency Injection and PHP](http://ralphschindler.com/2011/05/18/learning-about-dependency-injection-and-php) +- [What is Dependency Injection?](http://fabien.potencier.org/article/11/what-is-dependency-injection) +- [Dependency Injection: An analogy](http://mwop.net/blog/260-Dependency-Injection-An-analogy.html) +- [Dependency Injection: Huh?](http://net.tutsplus.com/tutorials/php/dependency-injection-huh/) +- [Dependency Injection as a tool for testing](http://www.happyaccidents.me/dependency-injection-as-a-tool-for-testing/)