views:

62

answers:

2

I'm trying to hack my own dependency injection container in PHP, based on constructor injection. The container instantiates complex objects and inject them with the required objects based on the type hints in the constructor using reflection.

One thing I obviously stumbled upon is the fact that I can register multiple components that can be injected, of the same type (extending same class / implementing same interface(s)). For example, what if two objects both need distinct objects that both implement an Iterator interface. How do DI Containers typically deal with this? How do you let the container decide which of the objects with the ambiguous interfaces need to be injected in which of the complex objects?

Or is a single DI container only ment to be responsible for creating one type of complex object? In other words: for each complex object instantiate a distinct DI container. I can hardly imagine this is the intent, right?

+1  A: 

What you're describing isn't DI, per se, but rather autowiring, a step further than plain DI. Normally with DI you explicitly configure which components get wired into what.

Autowired DI is only really desirable with coarse-grained components, where there's only one sensible implementation of the given type (e.g. DAOs). In cases where the type is ambiguous, then you either mark one of them as the "primary", or mark the others as "not candidates", or explicitly mark the dependency with the name of the component you need.

If it helps, you could read up on how Spring handles autowiring here and here

skaffman
Skaffman, thanks for the clarification. I didn't know this was known as autowiring. But that sounds sensible. I guess I should go with your last proposed option then, because the other options will probably cause undesired effects in the long run. I'm trying to make it a much bulletproof as I can. Back to the drawing board. :)
fireeyedboy
Surely there must be existing IoC frameworks for PHP?
skaffman
You are probably right. But I usually want to play around a little with these things myself (only to fall back on existing solutions later haha ;-), to help me get a better understanding of what it entails. Also I want to better my OOP skills, and like this for exercise. :)Thanks for the additional sources BTW. The first pretty much gives the options you gave and the conclusion I derived from that, in that I need to throw an Exception if there is unresolvable ambiguity.
fireeyedboy
+1  A: 

Depending on what you mean by your question, here's what Guice (a DI framework for Java) uses:

If you simply want a distinct object every time you have an injection request for Foo, then when wiring up your application don't bind Foo.class to a particular instance of Foo, but instead bind a Provider<Foo>, which is an object that creates a Foo on demand. Then, every place where Foo is injected will get a new instance. If you just bind Foo to a class instead of a Foo instance (say, Foo is an interface, and you bound it to RealFoo.class which is a class that implements Foo), you also get the same effect - a new instance is created every time. (This is the default, "unscoped" behavior. The behavior of Guice scopes is beyond the scope of this comment)

If however you need to have two instances of Foo that you construct when wiring up your application and then have the ability to say "This instance of Foo gets used when making a Bar or a Baz, whereas this other instance is used when making a Bumble", what you do is annotate the injection points and then when wiring up your app say something like:

Foo foo1 = new Foo("1");
Foo foo2 = new Foo("2");
bind(Foo.class).annotatedWith(Names.named("Bar")).toInstance(foo1);
bind(Foo.class).annotatedWith(Names.named("Baz")).toInstance(foo1);
bind(Foo.class).annotatedWith(Names.named("Bumble")).toInstance(foo2);

Where I assume that you've annotated the arguments to Bar's constructor with something like:

public Bar(@Named("Bar") Foo foo) { ...

And similarly for Baz and Bumble. Of course, if you annotate the constructor of Bar and Baz with the same thing, you can skip one of the bind lines.

I know there are annotation-processing frameworks for php based on reflection, or perhaps you can use a convention based on argument names.

Daniel Martin
O, that's an even more complex implementation than what I had in mind. I was not even worried about the same objects being instantiated with different injections yet (didn't cross my mind yet). Rather, I was referring to different objects that both need objects of the same base type or base interface injected, but which are actually different classes. (Pardon me for maybe mixing up the correct terms here).But your example puts things in a whole nother perspective all together. Good points. :)
fireeyedboy
BTW, I'm not sure I like the annotation options. I'ld like to keep it as 'clean' as possible, without having to change the subjects implementations. It should be able to work of the shelf with any objects, if you know what I mean. Constructor argument names, or better yet, explicitly naming the dependencies in the DI's configuration is probably the way to go.
fireeyedboy