My first stab at the Dependency Injection Container in Zend Framework 2

So, let me explain… no, there is too much.  Let me sum up.

With beta 3 now being released I have started to spend some time getting used to the new MVC components and the architecture in general.  I turns out that was too much.  When I learn something new I like to start with something broken and fix it.  This forces me to understand how things work a little better.  But I ran into a problem that MVC is so dependent on other concepts in ZF2 that until I understood those concepts I would be spinning my tires trying to get an MVC-based application running without much benefit.

So since I already know how to use event managers the next most basic thing I needed to understand was Dependency Injection.

It turned out that I was actually using Dependency Injection and just didn’t know it.  You know all of those iterative addElement() calls in Zend_Form?  Dependency Injection.  Getters and Setters like setPluginLoader() or setTranslator()?  Kinda the same thing.  Basically, if you don’t call the constructor inside of an object you are likely going to be injecting functionality into that object.  Whallah!  Dependency Injection.  While that does not encompass DI, it is a good starting point.

But one of the problems with manually injecting dependencies is just that; it is manual.  Need a view object?  Create and inject it.  Need to use it 20 times?  Create it once and inject it into any object that needs it, making sure to pass it around to any component that may need it.  It’s a bit of a hassle.

Enter the Dependency Injection Container.  What this allows you to do is write a class and maintain an instance of that class in a container so rather than making sure you have injected every dependency you just inject the container.  There’s more to it, such as creating definitions, but that’s all you need to know for a starting point.

Setting up DI is actually really easy.  Let’s start with a class.

1
2
3
class Test
{
}

Now let’s create our DI container

1
$di = new Zend\Di\Di();

Now let’s get an object

1
$test = $di->get('Test');

There you have it.  You are now using a Dependency Injection Container.  Instead of passing that Test object around to everything that needs it simply pass the container and you can get it, or any other object in the container, in one place.

So what if your object actually needs some data injected into it?  Add a constructor!

1
2
3
4
5
6
7
8
9
class Test
{
  protected $test;
 
  public function __construct($test)
  {
    $this->test = $test;
  }
}

Now to get an instance with data passed in the constructor we need to add the constructor parameters to the DI call.

1
$test = $di->get('Test', array('test' => 'value'));

If we do a var_dump() on $test we will now see that the protected variable $test has the value “value” attached to it.

The last thing we will look at is calling a setter.  Setters can have a little more complexity to them but the basic usage is very much the same.

Let’s start with our class.

1
2
3
4
5
6
7
8
9
class Test
{
  protected $test;
 
  public function setTest($test)
  {
    $this->test = $test;
  }
}

Now we call our DI container

1
$test = $di->get('Test', array('test' => 'value'));

And we get the object with the setter called.  Notice something?  We didn’t change the code to call the DI container.  What happened was because the container constructor was removed the DI container tried to find a proper setter for the key “test”.  That was called setTest() and so it called the setter and the value was injected.  So what happens when we have both a constructor and a setter?  With this code they are both called twice.

With that you can see some very basic usage of a dependency injection container.  While any application of any size will have more complexity to it these examples show that to get up and running with DI and a container are actually not very complex.  But while this is simple I will be going into much more depth in subsequent blog posts to expose some of the power that comes with using a DIC.

10 comments
Greg K
Greg K

So does passing a DI container around break the LSP? And lie about your class dependencies, instead of asking for what you need in your constructor, you're asking for a DIC instead?

Greg K
Greg K

 @Greg K Sorry, I wrote LSP (Liskov substitution principle) and meant LoD (Law of Demeter).

kschroeder
kschroeder moderator

 @Greg K As a matter of practice you generally do not want to simply pass the DiC.  What you want to do is retrieve the object from the DiC and have the DiC inject the dependencies (but not the DiC itself).  There may be some circumstances where the DiC may be asked to inject itself into a requested object, but the goal is generally to minimize those situations.

Latest blog post: Looking For Local Radio Shows

lsmith
lsmith

 @Greg K absolutely .. passing the DIC to your objects is turning the DIC into a registry.

lsmith
lsmith

As you point out you are just now learning about DI/DIC, but just for the record "Dependency Injection.  Getters and Setters?  Kinda the same thing.  Basically, if you don’t call the constructor inside of an object you are likely going to be injecting functionality into that object." is confusing the topic at hand.

 

There are various ways of injecting, all of them are DI. Its not about constructor or not. The key idea is that instead of creating the dependencies inside the class, they are injected from the outside.

 

As many of the newer PHP frameworks heavily build on DI and DICs, its a very important concept that needs to be fully understood in order to really leverage these frameworks to the fullest.

 

In your learning process I can recommend you two blog series on the topic:

http://fabien.potencier.org/article/11/what-is-dependency-injection

http://blog.astrumfutura.com/2011/10/zend-framework-2-0-dependency-injection-part-2/

kschroeder
kschroeder moderator

 @lsmith What I was doing was using the example of Zend_Form as a bridge.  I wasn't talking about getters and setters in general (I will clarify that), but rather that developers who have used Zend_Form (which I would presume many have) have already been using dependency injection, but just didn't know it.  

OptimusMarlboro
OptimusMarlboro

Thanks for the great article.

Looking at the following module config file

 

https://github.com/zendframework/ZendSkeletonApplication/blob/master/module/Application/config/module.config.php

 

What is the difference between "parameters" and "injections"?

 

Thanks again.

socalnick
socalnick

 @billyildirim It's a pretty simple distinction. Parameters will be used once as either a constructor parameter or setter parameter. You can be very specific about what method you want the parameter injected into by fully-qualifying the key. Injections are just a way to pass multiple items into an injection point. A great example is in the skeleton application, multiple resolvers are being injected: https://github.com/zendframework/ZendSkeletonApplication/blob/master/module/Application/config/module.config.php#L66

kschroeder
kschroeder moderator

 @billyildirim I will be going over that stuff over a series of articles as I become more familiar with how to use it.  At this point there are a lot of answers I DON'T have.  :-)

Post Navigation

Web Analytics