Zend Framework 2 comes with a dependency injection container (DIC), as does Symfony 2 and Aura, along with many other PHP frameworks that target PHP 5.3 or hight nowadays. This article attempts to explore the problem that a DIC tries to solve.
Consider this simple (contrived!) example of an Album object that has an Artist object:
class Album { protected $artist; public function getArtistName() { return $artist->getName(); } }
The question is how to we set the $artist member variable within this class?
There are a number of ways to do this. The easiest way is instantiate it directly:
class Album { protected $artist; public function __construct() { $this->artist = new Artist(); } // etc }
This is Not Good Code (TM) on a number of levels. The most obvious problem is that suppose that at some point in the future you create a new class, SoloArtist, that overrides Artist, then Album will need to be reworked to handle this situation.
Dependency Injection is the term used when you write more flexible code that allows the dependent classes to be changed without having to change the class' code. There are a number of different ways to inject the artist object into our album. The easiest way is to use a constructor:
class Album { protected $artist; public function __construct(Artist $artist) { $this->artist = $artist; } // etc }
The calling code then does this:
$album = new Album($artist); // do something with $album
One problem with constructor injection is that if your class has many dependencies, then your constructor signature gets unwieldy and hard to read.
Another way is to use setters:
class Album { protected $artist; public function __construct() { } public function setArtist(Artist $artist) { $this->artist = $artist; } // etc }
With usage like this:
<?php $album = new Album(); $album->setArtist($artist); // do something with $album
Now, when you have multiple dependencies that you need to inject, each one is a separate set method and so we don't have a long list of constructor parameters.
However, once you have multiple dependencies, the amount of code that you have to write to use this class gets bigger and bigger. As a result, if you use the class a lot, it ends up that you're writing a lot of extra boiler-plate code every single time; just to configure the class!
The solution to this problem is called a Dependency Injection Container.
A specific container for our Album class could look something like this:
class AlbumContainer { public static function createAlbum() { $artist = self::createAConfiguredArtistSomehow(); $album = new Album(); $album->setArtist($artist); // more setXxx() calls here return $album; } // more methods as required }
(obviously, this example glosses over a number of real-world considerations...)
Now, to instantiate a new Album object, the code is:
<?php $album = AlbumContainer::createAlbum(); // do something with $album
This makes using the class easier and gives us all the benefits of decoupling our dependencies. Having to write a new container class for every object gets old very quickly though and so to solve that, generic dependency injection containers have come into existence.
Hence, a dependency injection container is simply a component that holds dependency definitions and instantiates them for you. That is, it stores configuration information about which dependencies any registered class has and instantiates them according to the definition provided.
Don't write your own though; use one of the many that are out there!
(Yes, I know that there's many many posts on dependency injection out there. There's always room for one more though! I also recommend perusing Fabien Potencier's Dependency Injection with PHP 5.3 talk slides)


