Dependency injection container basics

I have to make this quick cause I’m at work, so please bear with me. :stuck_out_tongue:

I’m a huge fan of DI, I almost exclusively use this practice, except in my models because of the great number of dependencies sometimes needed I often skip DI or any IoC technique and simply instantiate the service inline as required.

Can someone (Marcus?) give some real life examples as to how a DiC might save me some trouble, so I can go about implementing a basic DiC framework in my own code.

Lets use a model as an example and the following dependencies:

  1. Locale
  2. Mailer (SMTP)
  3. Table data gateway

Part of what confuses me is how a framework like Phemto understands how to initialize a complex service like SMTP mailer with the HTML message types, connection details, etc? Would you wrap this funcitonality in a facade and use that as the dependency???

Cheers,
Alex

Now, to make this work, you need to separate your objects into two kinds; Those that can be created at startup and those that needs to be created in runtime. I like to call them Shared objects and Transient objects.

Thanks. As scary as it may sound, I actually came to the same conclusion myself. I just don’t see the value of having to define which shared objects are used by which other shared objects up front.

Part of it is your fault. About five years ago I took a pretty in depth look at your Konstruct code. The one thing I took away from it was the notion of having each object pass a context object down the creation chain. My context object contains some wiring code similar to that used by injectors to make it easy to control which classes are used to create the shared objects. The context is also basically read only so you don’t have the problem of wondering where changes to it come from.

This is the part that trips me up a bit.

$injector->create('SignUp') 

To me it implies that the injector instance needs to be passed along to every object that needs to create new objects. So how does one go about injecting the injector as it were?

Care to elaborate on that a little? Having an object which exists but in an unusable state until you call specific methods on it seems messy. It forces error checking into the client code, encourages inconsistent return types and puts extra “is x dependency set yet” checks into the object itself because it can’t rely on its dependencies being set.

I agree that most objects should be usable after instantiation, but in some cases I may want an object re-initialized after construction, a Mailer object as a possible example.

I instantiate a mailer object in my model, but have a connection pool to iterate over to distribute mass mailings over several SMTP servers.

In this case I would not want to initialize the object with a default connection incase something happens and a connection isn’t needed anymore. I would call a connect() method inside a foreach() with different connection settings every X number of emails sent.

not saying I would do this just saying it’s a possible example.

Cheers,
Alex

Some containers can inject dependencies through setters. This can be used for cases where you have deep hierarchies. Or you could use delegation, rather than inheritance.

In Konstrukt, framework-level dependencies are actually injected through setters, exactly to keep the constructor free to use by the application. See: http://github.com/troelskn/konstrukt/blob/master/lib/konstrukt/konstrukt.inc.php#L50

The issue is: when you start using inheritance with DI, you’ll have to pass all of the dependencies of the parent to the child, even if the child doesn’t use them at all.

If the child class didn’t use them at all, why would you override the constructor()? If the child didn’t use them, could you not just use the base class ctor()?

This is one more reason to stay away from inheritence, especially in controller hierarchies, IMO.

Cheers,
Alex

hmm i just tried it, perhaps I was mistaken. Either they fixed it or my memory is bad (probably the latter ;), but i’m sure i’ve seen “__construct should be compatible with…” oh well )

Hi…

This is just broken. The constructor is not part of the interface, ever. They should fix this.

yours, Marcus

While writing the above response, it becomes painfully clear that I could simply abstract that shared functionality out into another object which can be injected, instead of using inheritance. Hm. Maybe I’m just being an idiot.

Or stick with inheritance and add an extra level in between which defines the common behavior of “most” of your classes. Let them extend from that, let others extend from the top level one.

That’s another possibility, although that will probably drive me mad before the end of the day. Well, more mad then what I usually get myself anyway. I’ve done the thing you’re suggesting once and it became a mess: when the classes inherit from different classes, while they are the same type of classes in my head, I get freaked because adjustments in base class X don’t reflect in child Y, and that’s because Y inherits from Z, not X. I avoid inheritance trees as much I can, because of that.

Could well be I’m just incapable of keeping all of the stuff in my head. The last time I tried having multiple inheritance paths I was very inexperienced, so that is probably a big factor. Oh well.

Yes, they should.

I know. I’m having a hard time explaining myself. I should look into the issue further, maybe, just saying this is something I’ve ran into recently.

Ah, good question. It’s code reuse, so I am in effect abusing the inheritance tree so I don’t have to write the same code in each controller. I assume you are aware of classes such as Zend_Controller_Action, or k_Component? You have to extend those classes to use their default functionality.

Once you start writing the application, it becomes clear that almost every child needs an instance of Foo, and it becomes clear that they all have some shared functionality, so it makes sense to build another abstract controller which the concrete controllers can extend from. It’s a hack I need, because there is no such thing as horizontal reuse in PHP yet.

Oh. While writing the above response, it becomes painfully clear that I could simply abstract that shared functionality out into another object which can be injected, instead of using inheritance. Hm. Maybe I’m just being an idiot.

Sorry, I don’t follow that. It doesn’t use them, but it still does? But that is what I’m saying: not every child of the abstract controller actually uses the dependency, but enough of them do, so it’s worth the effort of putting it in the base.

If I have the time, I’ll try abstracting the common functionality, and nuking the layer in between, I think that would result in a much cleaner design. Thanks, needed a little help to overcome this brainfart :wink:

Hi…

Yes, but mainly no :).

Suppose you are staring at this bit of code trying to find a bug in “…”:


do_stuff($registry) {
   ...
}

Where in the code will it be?

First check the code itself. Trouble is, there are lot’s of calls to $registry->thing in there.

Well, one of the registry objects could be set up wrong. OK, check every object. Trouble is, they could be using the registry too. Mock them? What to mock? Using print_r() to inspect the registry is going to get you acres of screen dump, so that’s out.

Who could have set up the registry wrong? Every piece of code that had access to the registry, which is every significant piece of code.

So, the bug is somewhere in your app. Great :(.

Compare this with:


do_stuff($thing1, $thing2) {
   ...
}

Assuming no globals or Singletons or use of the “new” operator in complicated bits of code, your problem of finding the bug is easy. It’s the caller or it’s in the “…”. You can proceed in a straight line to the bug.

I’ve used a function here, rather than a class, but you get the idea.

A ServiceLocator is an improvement over the Registry, but if a dependency is messed about with by other code, you are in the same boat. Fundamentally the same problem, but at least easier to cope with in practice.

DI means passing all dependent code. No secrets. This gets you very long constructor lines, so a DI tool (no idea why it’s called a container) takes the pain from that and reduces lot’s of duplication of nested "new"s or lot’s of little factories.

Yes, but that’s not the goal in itself. It’s to make dependency passing workable. But yes, you’ve got it as far as I understand it.

What happens as a result of this are lot’s of really nice things. Dependencies can be moved around freely and their lifecycles are under the control of the application developer rather than the library writer.

I think this is an active area of research. It is for me :).

yours, Marcus

Just a quick question, I understand DiC to basically be a service locator/registry on steriods, but with the ability to resolve dependencies.

I basically see implementing something that does:

  1. Instantiate DiC object
  2. Register various dependencies
  3. Use DiC to instantiate primary object of interest
  4. DiC determines which depenencies primary object must have injected
  5. DiC instantiates first dependency and injects into ctor() of primary object

OK so a bit a misleading description, because obviously resolution of depenencies must come first if we are to inject dependencies at ctor().

Is this the basic principle behind a DiC? Basically removing the complexity associated with wiring up complex dependencies and automatica resolution of dependencies?

So no long would you possibly end up with:


$obj = new Primary(new Secondary(new Ternary(), new Config('test', new Setting())

// Instead you have something like:

$DiC = new Container();

$DiC->register('primary', 'Primary')
$DiC->register('secondary', 'Secondary')
$DiC->register('ternary', 'Ternary')
$DiC->register('config', 'Config')
$DiC->register('setting', 'Setting')

$obj = $DiC->fetch('primary');

$obj->doSomething();

I guess what confuses me, is what happens when you have an object which requires additional ctor() arguments, such as connection details?

Hopefully I’m making some sense, cause I have to admit I’m confusing myself with more question. :stuck_out_tongue:

Cheers,
Alex

That’s the part that most people don’t get. It’s hard to convey in sample code, but the main idea of a container is that you only use it at the top level of your application (The bootstrap or whatever you call it). Everything else is unaware of the container. So you would never actually see code like this:


$container->create('DatabaseConnection');

It would always be a higher level object. Something like:


<?php
require_once 'globals.inc.php';
$controller = $container->create('ArticlesController');
$response = $controller->execute();
$response->output();

Now, to make this work, you need to separate your objects into two kinds; Those that can be created at startup and those that needs to be created in runtime. I like to call them Shared objects and Transient objects. Typically, Shared objects will be things that you might think of as being globally unique (Singleton candidates), whereas transients can have many instances in a runtime (For example a entity in the model layer). Using DI forces you to keep the two separated, so you’ll find that certain patterns are very hard to fit in; For example, active record doesn’t play very well with DI.

This is IMHO the main benefit of DI, because it forces you to write your code in a way that is eventually much easier to maintain. You have to separate application state from things that have lasting side effects. You probably have to grok it before it makes sense. And I know that’s a really annoying thing to say, but I believe that it’s true.

Care to elaborate on that a little? Having an object which exists but in an unusable state until you call specific methods on it seems messy. It forces error checking into the client code, encourages inconsistent return types and puts extra “is x dependency set yet” checks into the object itself because it can’t rely on its dependencies being set.

I tend to place application specific information in the wiring file. So a company wide mail address I’d place there, or paths to files within the version control export. I make a big distinction between this information and the machine specific server stuff.

This seems odd to me. Putting what are essentially application specific configuration options in the wiring file seems like a violation of separation of concerns and for anyone looking at the code wanting to change the email address would be confusing to locate, imho.

Do you do the same with database connection info? I like to keep an single configuration file with all these application specific config options, simply to keep everything together in an easily readable/editable format.

Then you have the problem of the object not being fully initialised after it’s constructed. Your setters have become additional constructors (you can’t do anything with the object until the setter has also been called). Imho this is worse than long constructor arguments as it creates ambiguity. Can you be certain that any instance of the object being passed around is fully initialised?

Essentially the object is superficially aware of that it will be created by a DIC. You know that it’s going to be correctly initialised by the DIC so it doesn’t present any issues… at least where the DIC is creating it. Take that object out of the DIC comfort zone and anywhere the object is used there is ambiguity about its state.

Imho this is worse than long constructor arguments as it creates ambiguity. Can you be certain that any instance of the object being passed around is fully initialised?

Personally I see ‘created/instantiated’ and ‘initialized’ as potentially different. Although I do agree dependencies should be injected at construction.

Cheers,
Alex

The issue is: when you start using inheritance with DI, you’ll have to pass all of the dependencies of the parent to the child, even if the child doesn’t use them at all.

This doesn’t really make sense. Either: the child really doesn’t need them, in which case why is it inheriting from the parent(Sounds like it has different behaviour)? or what you mean is that none of the methods defined in the child class use them, which isn’t a problem either because methods using them can still be called on the object, so it does still need them.

Hi Marcus,

You’re not, and this would actually solve the problem. I’m afraid I’ve simplified the issue at hand though, so it’s not just the User that gets passed in, it might be a whole lot more. That ultimately results in a long list of constructor arguments, of which any number may or may not eventually be used by the child class. Without the container doing it’s magic, I would probably opted for passing the dependency to the method that actually needs to have the object, e.g. authenticate( ), but then the objects would be lazy loaded through a registry-ish object.

The issue is: when you start using inheritance with DI, you’ll have to pass all of the dependencies of the parent to the child, even if the child doesn’t use them at all.