Dependency injection and Zend Framework

Lately I've been working on a site based on the Zend Framework. It's been a good chance to get more intimate with ZF, learning the inner workings and quirks of the framework. Today I came across the question of how to do dependency injection for your controllers - I was looking for a way to rid the code of the 'new' keyword as well as static methods, coupling things more loosely.

Controllers aren't meant to override the __construct() method in ZF - sure you can do it, but there are meant to be better ways. That leads to the question: how? Well, if you do have a look at the __construct() method of Zend_Controller_Action, you'll notice that it takes three parameters. The last one is the interesting one here: it's an array called invokeArgs. This should immediately set you off testing what gets passed in - a bunch of goodies, it turns out. Among other things, you'll be getting a copy of the Bootstrap object.

ZF Controller Dependency Injection, #1

The above leads to the first, not too good way of injecting things. Just stick whatever you want injected into the bootstrap object - your controller has access to that through the invokeArgs parameter. That's not a very good solution though, as you'll be breaking the Law of Demeter: your controller needs to know that your injected param sits inside the bootstrap element, so you'll be accessing the injected elemented indirectly. Not nice.

ZF Controller Dependency Injection, #2

I googled a bit and came across Dependency Injection and Zend Framework Controllers, which has a nice solution to the problem. As the param name suggests, invokeArgs can be modified - you can add to the args to your heart's content. You need to use the setParam() method of Zend_Controller_Front - so, in the bootstrap object for instance, you can do the following:

$front = Zend_Controller_Front::getInstance();
$front->setParam('factory', new MyFactory);

Your object will then get passed to the controller in the invokeArgs array. You can access this either through \$this->_invokeArgs['factory'] or the getInvokeArg() method of Zend_Controller_Action - the latter being preferable.