PhpRiot
News Archive
Related Articles
PhpRiot Newsletter
Your Email Address:

More information

Zend Framework 2.0: Dependency Injection (Part 1)

Note: This article was originally published at Planet PHP on 5 October 2011.
Planet PHP


Image via Wikipedia

If you've been watching the PHP weather vane (we call it Twitter for short), you may have noticed a shift in Symfony and Zend Framework. Version 2.0 of both web application frameworks feature Dependency Injection Containers (DICs) as the primary means of creating the objects (and even Controllers) your application will use. This is an interesting shift in a programming language that often stubbornly evaded adopting DICs to any great extent. In this mini-series of articles, I'll take a look at the marvellous world of Dependency Injection as we run up to an examination of Zend Framework 2.0as Zend\Di component in the next part.

What is Dependency Injection (DI)?

The short answer to this question is that Dependency Injection is a design pattern where, instead of dependent objects creating their dependencies internally, they instead define setters, constructor parameters or public properties which allow a user to aoinjecta dependencies from the outside into the dependent object and where such dependencies adhere to an expected interface.

If the definition sounds familiar, it's because Dependency Injection is an obvious design pattern. As a programmer who knows how to use PHPUnit, you probably use the pattern every time you open an editor. So let's quickly look at why the pattern is both obvious and ubiquitous.

Imagine a class implementation called Leprechaun. In writing the class, we realise we have a dependency on another class called PotOfGold. A naAve implementation would start out very simply with the Leprechaun object creating an instance of PotOfGold for use.

If you think this through, you may notice the problems. What if we want our Leprechaun to instead have a PotOfRareEarthElementsFromChina? What if we need to replace PotOfGold with a mock object during unit testing? What if another users locates a bug in PotOfGold and needs to replace it without editing the original class (since it's under 3rd party version control)?

The answer to all these questions is to allow external parties to inject dependencies instead of relying on the object to create them internally. Based on our ridiculous example from above, we would define a setter called setPot(), and allow it to accept any object which implements a new Pot interface. Using an interface merely ensures the dependency that is set obeys some interface the dependent object is expecting.

That, in a nutshell, is why Dependency Injection is obvious. It's a simple shuffling of creational responsibilities from within an object to some external agent which makes the dependent object more flexible, testable and amenable to the wisdom that Composition is preferred over Inheritance (i.e. injecting objects beats monkey patching!).

Some External Agent

In applying Dependency Injection, we eventually reach a state where all objects in a system are created by a mysterious external agent. What is this entity?

One possible candidate is whatever passes for a Controller in your framework based application. In Zend Framework, this would be an instance of Zend_Controller_Action. Our Controller, in this instance, would define an action method which would perform a necessary application task and create all the objects needed to perform that task. This makes a lot of immediate sense to programmers since allowing you to write Controllers with as little fuss as possible is a fundamental goal of any framework.

However, Controllers are objects! If you had a NewsletterController defining an emailAction method, you might expect that creating an instance of Zend_Mail inside that action is obvious (which it is). Think again! In Dependency Injection parlance, your Controller is a dependent object and an instance of Zend_Mail is one of its dependencies. This is no different fr

Truncated by Planet PHP, read more at the original (another 8332 bytes)