What Application Layer Does A DI Container Belong In?

By | February 11, 2014

James fuller asks:

any thoughts about which layer of the application we should be using a DI container like Aura.Di? Highest layer possible?

Twitter is too constrained and ephemeral for a good response, so I’ll answer that question here.

First, we need to remember that a Dependency Injection container and a Service Locator are indistinguishable from an implementation perspective. (This is a view I accepted only recently.) The difference is in their use: if a container is ever placed into an object so the object can retrieve its own dependencies, that container is being used as a Service Locator. Conversely, if the container stays entirely outside an object so that dependencies are pushed into the object, the container is being used for dependency injection.

If we accept that description, the proper layer for a DI container is outside every other layer in the application (with the possible exception of Factory classes). That means the DI container is part of the bootstrapping code that sets up the application, and not part of anything else.

As an example, we can imagine a web application bootstrap script that looks like this:

<?php
// set up the autoloader
include '/path/to/autoload.php';

// create and set up a Container
$container = new Container;
$container->load('/path/to/container_config.php');

// retrieve a front controller service and run it
$front_controller = $container->get('front_controller');
$front_controller->exec();
?>

The purpose of the bootstrap is to create and configure the container with all its services and settings, then pull one object out of the container and invoke it. None of the objects in the system has to know that the container even exists. All of the objects are being created via the container, so in a way the container “contains” the entire object graph.

The part I had the hardest time getting about real dependency injection was this: If you have a class 2 or 3 layers down in the application, and that class needs dependencies, how do they get injected? Don’t you have to pass the dependencies through the intervening layers, and then doesn’t that break a lot of rules, along with violating plain common sense? And what if that class needs access to several different but related objects, but doesn’t necessarily know what they are in advance?

The key for me was realizing that all object creation work happens in the container and not in the classes themselves. This is an alien way of looking at things for most PHP developers, who are more used to Singleton, Registry, and Service Locator, not to mention static calls to ActiveRecord objects. All of these patterns of usage mess with separation of dependencies, but are very common in PHP land, and form the basis of most PHP developers’ understanding of how to work with dependencies.

It took me a year to really “get” the concept of dependency injection, under tutelage from guys like Jeff Moore and Marcus Baker, along with the writings of Misko Hevery. Once I understood it, I wrote the Aura.Di readme file as an introductory document to step readers through the various stages of dependency allocation. Perhaps that document will be helpful to others, even if they don’t choose Aura.Di as a container.

Afterword

If you work with a legacy application, you already know how hard it is to track dependencies throughout the code. Sometimes the dependencies are global, sometimes they are created inside that class that needs them, and sometimes there is a service locator implementation floating around inside the classes. This makes it frustrating to track down bugs and make wide-ranging changes, and terribly difficult to write tests because everything depends on everything else.

But it doesn’t have to stay that way. My new book, Modernizing Legacy Applications in PHP, gives detailed instructions that will lead you step-by-step from an include-oriented mess of page scripts to a modern architecture using dependency injection techniques.

You can buy the book in early-access mode today, or sign up on the mailing list below to get more information as it becomes available!

Sign up for Modernizing Legacy Applications in PHP:

First Name Email

11 thoughts on “What Application Layer Does A DI Container Belong In?

  1. cordoval

    I believe the layer is the one above the previous to the top one on your application. Say a kernel, like in symfony. In the example above we are talking about a script which mixes the construction with the autoloading etc. So this definition works better for all cases. I am totally with you on the service locator/DI difference and how you explained it.

    Reply
  2. Phil Bennett

    It depends on what you’re building I think, I would say if you’re comfortable with architecture etc it should be the top level (with exception of autoloading) with itself being injected in to factory based classes such as routers/dispatchers etc…

    Reply
  3. Pingback: Paul Jones: What Application Layer Does A DI Container Belong In? | htaccess

  4. Pingback: Paul Jones: What Application Layer Does A DI Container Belong In? | facebooklikes

  5. Adrian Miu

    This means that, in your application code there should never be a call to “new”? If so, how can you create a modular application that loads modules that have their own “dependency-container” entries. The example provided suggests the dependency container creates the application object that is executed but the application object is not aware of the container.
    How can you bootstrap additional modules (eg: you must query the database to see which modules are installed and available) that have their own DI Container rules without passing the DI container from the app to the modules?
    If you have any experience with ZF2, imagine having to configure modules without them having, AT ANY POINT IN TIME, access to the service locator.

    Reply
    1. pmjones Post author

      > This means that, in your application code there should never be a call to “new”?

      Not quite; it means that, with a very few exceptions, only Factory classes should be calling “new.” (It took me a while to come around to that view when it was first introduced to me.)

      > how can you create a modular application that loads modules that have their own “dependency-container” entries.

      We’re back to Factory classes again. Maybe I should write up a post about that.

      > How can you bootstrap additional modules (eg: you must query the database to see which modules are installed and available) that have their own DI Container rules without passing the DI container from the app to the modules?

      If you have to query the database for that kind of thing, yeah, you’re going to have some troubles. That’s not a situation I’ve been in before so I’d have to think about it for a while to come up with an answer (if there even *is* an answer). And to nitpick, if you’re passing a Container around, it’s not DI anymore, it’s Service Locator. ;-)

      Reply
      1. Adrian Miu

        Any “decent” CMS out there (WordPress, Magento etc) have a way to store (usually in the database) which modules are enabled since some modules are included in a specific folder but not enabled. When you call `$front_controller->exec();` every enabled module should be loaded (ie: have their dependencies defined in the container).

        Maybe you can have other processes be executed between the DI config and execution of the front controller (like $container->get(‘moduleLoader’)->exec()). But that would mean you have 2 apps running (the $moduleLoader and $frontController)… which is not wrong, but different “one app to rule everything” approach

        Reply
  6. Jacob Greenleaf

    > If you have a class 2 or 3 layers down in the application, and that class needs dependencies, how do they get injected? Don’t you have to pass the dependencies through the intervening layers, and then doesn’t that break a lot of rules, along with violating plain common sense?

    Miksko Hevery, as you mentioned, addresses this very question but I’m not sure he agrees with you that Service Locator is the correct pattern.

    http://www.youtube.com/watch?v=-FRm3VPhseI#t=1883

    Reply
    1. pmjones Post author

      I don’t agree that Service Locator is the correct pattern either ;-)

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *