Zend Framework 2.0: Dependency Injection (Part 1)
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.0’s 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 “inject” 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 naïve 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 from our Leprechaun example. If we create the Zend_Mail instance inside the Controller we get the same irritatingly stubborn question. How do we replace the Zend_Mail instance with an alternative, test double or monkey patched version containing an emergency bug fix?
Controllers, alas, are not the external agent we’re looking for to create objects. And yes, you really should be testing your Controllers ;).
The next entity a level above Controllers can be loosely termed the Bootstrap. In Zend Framework 1, this started out as a relatively simple script to do just enough that you could start the FrontController and dispatch a request. In other words, Zend Framework traditionally did not offer a final external agent as needed for Dependency Injection. It left it to individual users to create something of their own or, as became inevitable, to just create objects in the Controllers themselves.
More recent Zend Framework versions offer Zend_Application, a method of bootstrapping that allowed users to define Resources, i.e. using a method or class which created an object (and injected its dependencies) and returned it on demand when it was needed by a Controller. This was the first consistent approach to handling object creation in ZF which effectively involved defining any number of Factory classes or methods in one location and passing the managing object (the Bootstrap) around the application wherever specific objects needed to be retrieved. In effect, this was a Dependency Injection Container. So, surprise, users of Zend Framework already have a DIC. An even lesser surprise: Zend Framework 2.0 will be no different.
Dependency Injection Containers Are The Devil
The concept of a Dependency Injection Container (DIC) is to act as a programmable object assembler. You take your DIC, tell it how to construct objects (including how to construct and inject their dependencies), pass the DIC to wherever it’s needed, and eventually ask it to create an object it knows about. This is not rocket science. DICs are simple animals to understand, however the devilish suspicion that PHP developers have for DICs is not rooted in what they do but how they do it and whether they make a developer’s life easier.
There’s a widely known belief that the Ruby language doesn’t need a DIC. I’ll use Ruby as an example because it has a few features PHP programmers can salivate over (like how it uses a new method for classes vs PHP’s new keyword making class subsitutions stupidly easy). One investigator of Dependency Injection from the Ruby world is Jamis Buck. For Ruby he wrote two DICs: Copland (a port of Java’s HiveMind) and Needle (it’s like Pimple on steroids which…defeats the purpose). After fighting Ruby for a few years, he finally gave up on trying to write a Ruby DIC and documented his thoughts on his blog in “LEGOs, Play-Doh, and Programming“.
The core lesson from the article holds true even in PHP – by and large, complex DICs are a complete waste of time in most scenarios. Indeed, if you ever use a DIC and discover it requires just as many (if not more) lines of DIC code and configuration as it would to do the same thing in plain old PHP, you should start asking where the fabulous benefits have vanished to because it’s not delaying the onset of cramped finger muscles as advertised.
Most PHP developers understand this instinctively. Unlike Jamis, most PHP programmers probably won’t have a strong Java background. As a programming group, we’re less inclined to assume we need a special DIC blessed by the PHP Gods so we fall back to whatever strikes us as a simpler solution.
But here’s the rub – the simplest solution is itself a DIC.
In referring to Dependency Injection Containers as the devil, cursing their name, and blaming them as Java imports designed to make life more complex than needed, it’s easy to lose sight of the fact that such criticism is about the implementation of DICs and not their actual function. There is nothing wrong with having object assemblers – we use them all the time and call them Service Locators, or Factory Classes, or Zend_Application (Resources), or any of a dozen terms slightly different and probably not entirely accurate. Most of the time we’re trying to create a DIC without being aware of the term.
Needles and Pimples (It’s Not What You Imagine)
Jamis Buck hit the nail on the head back in 2004 with the creation of his Needle DIC Ruby. Instead of creating something inspired by Java that relied on static configuration and too many features, he realised that Ruby excelled (as does PHP to a growing degree – thank Closures) in expressing logic through a Domain Specific Language (DSL). The result was a DIC captured by a simple DSL – well, until he went and overcomplicated it (read his article).
You can see the exact same fundamental simplicity that a DIC is capable of in PHP. It’s a small so-tiny-you-won’t-believe-it DIC called Pimple. Try calling that complex, hard, stupid or any other adjective you might instinctively think of when faced with the term “Dependency Injection”.
The core of Pimple is that you define object creations as closures. This immediately resolves a few traditional DIC problems. There’s no static configuration, you hand code all creation logic exactly once, and objects are named services you can recall and inject into other objects from your closure bodies. It basically takes everything you’d do in creating objects by hand and captures it all in one container. Other than the fact I hate arrays (my version uses object properties instead – it’s 50 lines; nobody was killed during its 5 minute development period), Pimple is like Dependency Injection itself – so blindingly obvious you may kick yourself.
Pimple proves that DICs are not the devil – they can be incredibly simple and useful tools if you can tame the urge to complicate it’s implementation.
Then There Were Frameworks
As you can probably see, making a strong case for DICs is not hard. Dependency Injection is obvious and omnipresent in PHP. Dependency Injection Containers can be a simple 50 line class you can write over a coffee break. The going gets tough when the simple notions we desperately want to cling to meet the complexity of PHP’s now standard tool: the application framework.
Frameworks: Not Written By Monkeys
As we’ve already covered, Zend Framework 1.0 covered off the external agent problem in Dependency Injection by creating Zend_Application. As Zend Framework 2.0 moves towards beta, it also needs a Dependency Injection Container to do similar heavy lifting. This time around, we called a spade a spade and the O’Phinney/Schindler hive mind wrote Zend\Di\DependencyInjector.
The DICs used by Symfony and Zend Framework are not like Pimple. Symfony’s DIC is driven by static configuration (preferably YAML for brevity). Zend Framework 2.0’s DIC is driven by a PHP API (no static configuration). Both have their own set of performance boosting measures to minimise any overhead in using a more complex DIC.
In the next part this mini series, we’ll take a deeper look at Zend\Di and see how it fares compared to Pimple or Symfony 2. In the meantime, I hope I’ve busted a few apprehensions you might have about using a DIC ;).
|Print article||This entry was posted by padraic on October 4, 2011 at 2:05 pm, and is filed under PHP General, PHP Security, Zend Framework. Follow any responses to this post through RSS 2.0. You can leave a response or trackback from your own site.|