The SitePoint Forums have moved.

You can now find them here.
This forum is now closed to new posts, but you can browse existing content.
You can find out more information about the move and how to open a new account (if necessary) here.
If you get stuck you can get support by emailing forums@sitepoint.com

If this is your first visit, be sure to
check out the FAQ by clicking the
link above. You may have to register
before you can post: click the register link above to proceed. To start viewing messages,
select the forum that you want to visit from the selection below.

To me, once you hit upon this problem, then there isn't so much an issue to do with the container it's self, but the design of your architecture. More often than not, this is what I've learnt.

Another issue in regards to a static Singleton is that you'll find it harder to test for, so it's just a case of passing it around that gains you more flexibility in other areas that are not as apparent.

Instead of just using a registry, factory or service locator. You have a mix of all 3.

Something like:

(..)

Is this what you mean kyberfabrikken?

I'm not entirely sure, what your code in that post is supposed to do, so I don't really know if that was what I meant. Let me try with a more concrete explanation.

Most classes have dependencies on something, of which there will normally be just one in the application. Let's say, you're using a table data gateway pattern, so you have a UserGateway, which can load User objects from your database. The gateway needs a connection to the database, say a DatabaseConnection object. I'd then make the UserGateway take the DatabaseConnection as argument to the constructor. Eg.:

PHP Code:

class DatabaseConnection{// ...}

class UserGateway{ protected $db;

function __construct($db) {$this->db = $db; }}

So far, so good. Now let's assume that I figure out, that I want my gateway to use an identity map, to keep track of referential integrity. I implement the identity map as a separate object.

This poses a problem however. Since we have changed the constructor, we have hereby changed the interface of our gateway. We will now need to search our code for places, where the gateway is instantiated, and add the new dependency. This makes it tedious to alter the constructors signature. The solution is to encapsulate the constructor in a factory:

The constructor is now hidden away, so you can add or remove dependencies in a single central place. This implementation gives us a new problem though; Assume, that you add another gateway, say a Product (So your application has two datatypes -- Users and Products). You can add another table data gateway, ProductGateway. However, presumably, you only want to have one instance of each class, in your application. So the following wouldn't work, since you would end up with two instances of DatabaseConnection and IdentityMap, each:

The solution then, is to add a registry to the factory. A registry is simply a storage of instances. So, before instantiating a class, you would check the registry to see if there is already one, and use it if there is. You can implement the factory and registry as separate classes, or merge them into one. Since the registry is really just a container, we'll take the latter approach, and implement the registry as an associative array, on the Assembler class:

The get() method will return a class from the internal array (the registry), if it has already been created. If it hasn't, it will call the create() method, which delegates to createClassname. Thus, if you call get('database') twice, the following will happen:
First the method createDatabase() will be called. The result is stored in $registry, and then returned. The second time around, it already exists in the $registry, so it's just returned.
We not need to modify out factories slightly:

And that concludes -- You now have an assembler, which is capable of creating UserGateway and ProductGateway, without exposing the dependencies to the user, and without getting more instances than you need. And you didn't use any global variables, or static calls. All dependencies are passed in the constructor, so this is a form of dependency injection.

You still need to write a factory for each class in your application. There are two approaches to this problem. Either you try to automate your way out of it. For example, both gateways have similar signatures, so there's some potential for code reuse there. You could let them extend from a common baseclass, and make the assembler intelligent enough to use this, if no direct factory exists. You could also use a configuration language of sorts, and as a variant of this, you could use typehints and reflection.
The other option is to stop here. The amount of classes in any application is limited, and since you just need to write one factory for each, it's a rather affordable task, in exchange for the gain in simplicity and code clarity.

There is one problem left now. The above code works, when there is only a single instance, which can be resolved at creation time. Sometimes, you need to create multiple instances, during the run time of the application. Let's say for example, that the UserGateway returns User objects. Each of these are created at a later time, than the gateway. To solve this, you could pass the Assembler to the gateway. The gateway can then use the factory as it needs:

Note that, since we're passing in the assembler to the gateway, we could have saved passing the DatabaseConnection too. I chose to do it this way, to make the dependency more explicit. If you had in fact just passed the assembler, you would be using a locator pattern, rather than dependency injection.

Why do dependencies need to be passed into the constructor? Perhaps the constructor's signature helps to describe it's interface, but I do not think that having an Assembler know the intricacies of an object's dependencies is necessary.

Instead, what I propose is to pass the registry into the constructor of such lazy-loaded objects.

It is then the object's responsibility to load (from the registry) its dependencies in the constructor. That way, the object itself is the only class that has knowledge of its dependencies.

This system factors well into dynamic loading of classes at run-time. Circular dependencies can be determined elegantly at run-time as well. If anyone is interested, I can post sample code when I get back from work.

Why do dependencies need to be passed into the constructor? Perhaps the constructor's signature helps to describe it's interface, but I do not think that having an Assembler know the intricacies of an object's dependencies is necessary.

Instead, what I propose is to pass the registry into the constructor of such lazy-loaded objects.

It is then the object's responsibility to load (from the registry) its dependencies in the constructor. That way, the object itself is the only class that has knowledge of its dependencies.

This system factors well into dynamic loading of classes at run-time. Circular dependencies can be determined elegantly at run-time as well. If anyone is interested, I can post sample code when I get back from work.

Please post some sample code. It's always good to look at how other people implement things.

Why do dependencies need to be passed into the constructor? Perhaps the constructor's signature helps to describe it's interface, but I do not think that having an Assembler know the intricacies of an object's dependencies is necessary.

Instead, what I propose is to pass the registry into the constructor of such lazy-loaded objects.

That is called a service locator (Or sometimes just a locator). It works well, as you have noted, but it has two weaknesses. The first is, that you form a dependency on the locator, from your class. That is, you add a dependency, which wasn't there before. This is not a huge thing in it self, but it's still a price to pay in terms of complexity.
The other problem, which I think is far more problematic, is that the dependencies are less explicit. You can't know which dependencies a given class has until at runtime (Or by manually analysing the code). That makes the code less obvious to use.

One hybrid pattern, is to use a dependency injection container, like the one I described in the above post, but implement the factory as a static method on the class it self. That way, the default factory is in the class, but the user of the class will not call this directly. To pull this off, you will need to make the assembler call to the class' factory, passing itself (Acting as service locator), so the factory can pull the dependencies needed. Eg.:

That is very interesting solution kyber. I have something very similar, but it differs slightly, and fundamentally in the implementation of the static factory method. I think the idea can be expanded slightly to offer the benefits of both worlds.

Disclaimer: Not having read any of the books normally quoted, excuse my naming decisions.

// This function can be overridden to use kyber's more explicit
// dependency system
public static function create(Locator $locator) {
return new self($locator);
}
}

Voilą!

PS:
Although I have not 'read the books', I don't think that this could be called dependency injection per se. It is more of a dependency pulling system, whereas dependency injection is more of a push system.

Not having found a reasonable antonym for injection, could you call this dependency acquisition? I don't know if it has quite the same ring, but nevertheles...

You can use an interface to make the contract explicit, if you like. I don't use that, because I decouple factory and assembler a little bit further, using a callback as the factory. With an interface, you make it tedious to attach make the factory user-definable. Most of the time, you will of course use the default (Class::CreateInstance) factory, but a container should allow for re-wiring. I use a callback as factory, which makes it easy to plug new factories in at runtime.

Originally Posted by b1ind

PHP Code:

// Default constructor accepts the locator
// This is the hybrid part :)
public function __construct(Locator $locator) {}

There isn't much hybrid over this. It's a clear-cut locator pattern. The static method is redundant though, you can just have the assembler call the constructor directly, if that's what you want. That also saves you from creating an abstract baseclass.

Although I have not 'read the books', I don't think that this could be called dependency injection per se. It is more of a dependency pulling system, whereas dependency injection is more of a push system.

The advantage of injection ("push") compared to ServiceLocator ("pull") is that class itself is independent on the particular wiring technique and isn't required to export specific functions to support it. Ideally, you could plug any (foreign) class into your setup without need to change or extend it ("plug and play", you know

We can roughly classify different wiring techniques as "pure injectors", "mixed" and "pure locators".

With "pure injectors" a class is complete unaware on what's going on, it's only required to have a sensible constructor declaration. Pure injector techniques include:

1. use reflection to automatically wire dependencies based on typehinting in constructor declaration (this is how phemto works)

And finally, a pure ServiceLocator (6) is what you wrote: constructor get a Locator as a parameter and pulls its dependencies out of it.

Which method to choose strongly depends on your particular application. For a small program with limited number of known classes, SL will work ok, however a bigger system with loads of foreign classes would require (1) or even (3).

It may be also useful to experiment with mixing approaches, e.g. (1) or (2) mixed with (5) looks quite interesting.

Ahh, very informative. I can see where the literature would have helped me. I think that I will personally continue with a locator-only approach.

I am curious, however, why DI becomes so essential in bigger projects. I am sure that I am not the only one wondering this. Is it because you cannot expect a constant constructor signature for externally-controlled dependencies?

Originally Posted by kyberfabrikken

There isn't much hybrid over this. It's a clear-cut locator pattern. The static method is redundant though, you can just have the assembler call the constructor directly, if that's what you want. That also saves you from creating an abstract baseclass.

The idea was that using the abstract base class, both became possible transparently. Granted, the interface is not necessary; it was meant as a definition of the contract.

Originally Posted by kyberfabrikken

You can use an interface to make the contract explicit, if you like. I don't use that, because I decouple factory and assembler a little bit further, using a callback as the factory. With an interface, you make it tedious to attach make the factory user-definable.

I'm unsure if you mean to explain how I use callbacks, or why an interface makes for an inflexible solution? I'll try to answer both, since they are connected.

Now, when I said that an interface made the solution rigid, I was being imprecise. It's not the interface, which is rigid, it's the object oriented style. Eg. the contract which gets explicit with an interface, but still exists when there isn't a formal interface.

Assuming that you wanted to be able to plug factories into the assembler at runtime, you could go an object oriented route, and define a factory interface:

PHP Code:

interface Factory{ function createInstance($class, $locator);}

Then extend the assembler to hold a map of factories, instead of hardcoding the call to CreateInstance() in:

You now have a container with factories attached dynamically (at runtime). That gives you great flexibility, however this implementation would require you to write a new class for each component you want to have a factory for. That's rather bureaucratic, so we need something a bit more smooth.

These factories have a simple protocol -- In fact they have just one method. This is a pattern, which is known as a command object, and it is the object oriented variant of a lambda. As long as it's stateless, it can be replaced with a delegated function call instead. The advantage then, is that you can group multiple such factory function together in a single class, instead of having multiple classes, each with one method. Behold: