Dependency injection and helpers

Hello,

I’ve been trying to get my head around dependency injection, which on the surface is a rather simple concept, however putting it into practise is easier said than done.

One issue I’m struggling with is how helper classes will get their dependencies.

A hypothetical example:
In an applications bootstrap it passes a request object to a router object, then passes the request and response objects to a front controller. The front controller instantiates the controller (based on the values set in request, by the router) passing the request and response, then calling the action. All very simple eh.

Now lets say this action needs to use a helper method that reverse engineers a route to generate a url. The helper would therefore depend on the router. How could the helpers dependency be met simply? I wouldn’t want to pass the router into the controller and I don’t really want to pass it to the helper in the boot strap.

It would be useful to get some ideas on how other would approach this.
It would also be good to see some opinions on the pros and cons of using a container verses constructor/setter injection.

Best Regards, George

The standard way to think of an application is presentation (MVC controller & view), domain (MVC model) and data access layers. Once you start experimenting with dependency injection I think that naturally leads you towards a fourth conceptual layer: object assembly. Wiring up the object graph is an important part of the application logic. When this is pulled out into a single location you can easily alter application behaviour simply by wiring up different objects. The DI container - which can be a simple factory - is like a party host which knows everyone and can introduce guests to other guests if it thinks they have something to say to each other.

Maybe the front controller should simply:
(1) examine the request
(2) configure the DI container (based on request info)
(3) ask the container for a controller instance
(4) $controller->go()

Because the container knows all the guests at the party (a kind of global scope) it can pass anything to anything. Does that make your problem disappear?

It would also be good to see some opinions on the pros and cons of using a container verses constructor/setter injection.
I think you’re comparing ServiceLocator with dependency injection? Martin Fowler is great but I disagree with his preference for ServiceLocator. To my mind, adding an extra dependency (on the ServiceLocator) is not good and outweighs any other considerations. Injection seems more elegant.

But just to confuse matters… you might need to pass a DI container around like a ServiceLocator. Maybe something needs either a Foo or a Bar but you don’t know which until the app is up and running. That’s the scenario outlined above. The front controller makes a decision, configures the injector, then makes a generic “give me the controller” call. With ServiceLocator, there is no configuration stage: instead the front controller would call different methods to get the appropriate controller object.

You might feel tempted to put some of this decision-making logic in the assembler/injector/container/whatever-you-want-to-call-it. I think you should avoid that. Assembler-things should do the wiring but nothing else. If you need some kind of conditional logic, pass them around to whatever knows how to apply that logic. Of course I could be wrong.

Also, note that it isn’t always the best choice to inject. The question is, who should have responsibility for choosing the implementation? I definitely, strongly recommend DI at least 90% of the time - perhaps more - but at other times it might make more sense not to expose that decision outside the client.

It is a very hard concept to fully grasp. Injection = commitment. Commitment is always a hard thing to allocate and decide upon.

Thanks for the fast replies.

McGruff, yes, that answers my question, I had some trouble trying to visualise the process.

I looked at a few of the simpler dic examples I found. I noticed that while most were able to provide an easy way to get an object, there didn’t seem to be anyway of passing parameters to the objects.

I come up with this, based on Fabien Potenciers Pimple


class DiContainer
{
    protected $_container = array();

    public function get($name, array $params = array())
    {
        if (!isset($this->_container[$name])) {
            throw new DiContainer_Exception($name.' does not exist in the container!');
        }

        return $this->_container[$name]($this, $params);
    }

    public function __get($name)
    {
        return $this->get($name, array());
    }

    public function __call($name, array $params)
    {
        return $this->get($name, $params);
    }

    public function set($name, Closure $func)
    {
        $this->_container[$name] = $func;
    }

    public function __set($name, Closure $func)
    {
        $this->set($name, $func);
    }

    public function asShared(Closure $callable)
    {
        return function ($c, $params) use ($callable)
        {
            static $object;

            if (null == $object) {
                $object = $callable($c, $params);
            }

            return $object;
        };
    }
}

Example use


$dic = new Guppy_DiContainer();

$dic->somename = function ($c, $p)
{
    return new someobject($c->anotherobject, $p[0], $p[1]);
};

var_dump($dic->somename('param0', 'param1'));

Is this sensible? I feel like I may be missing an obvious issue as it seems most di containers don’t support this.

I think you’re comparing ServiceLocator with dependency injection?
Yes I was. I was struggling to see benefits of this approach, but didn’t want to rule it out. The idea of a SeviceLocator, to me, seems like a glorified registry.

But just to confuse matters… you might need to pass a DI container around like a ServiceLocator. Maybe something needs either a Foo or a Bar but you don’t know which until the app is up and running. That’s the scenario outlined above. The front controller makes a decision, configures the injector, then makes a generic “give me the controller” call. With ServiceLocator, there is no configuration stage: instead the front controller would call different methods to get the appropriate controller object.

You might feel tempted to put some of this decision-making logic in the assembler/injector/container/whatever-you-want-to-call-it. I think you should avoid that. Assembler-things should do the wiring but nothing else. If you need some kind of conditional logic, pass them around to whatever knows how to apply that logic. Of course I could be wrong.

My temptation would be to do something like this (based on my above code).


$dic->controller = function ($c, $p)
{
    return new $p[0].'_Controller'();
};

That seems really messy though. Another idea would be to have a sub-container for all the different controllers. That seems like a maintenance nightmare, although it does sound more like the right way to do it.

I think my best bet is to build a basic framework utilising di. That way I’ll have a better idea of what issues can arise so I can develop with those in mind if I decide to use di in any client sites.

Best Regards, George

Hi…

I think Myself and McGruff had more debate about this than any other issue :). A hugely important use case.

yours, Marcus

If you haven’t already seen it, this is well worth a look:

http://components.symfony-project.org/dependency-injection/

djones, cheers for the link, some great information there, not to sure about the whole xml/yaml stuff though. To be honest I think that implementation is great for a framework like symfony but overkill for most sites, i may be wrong though.