Dependency Injection Container

Some headaches later I think I found a nice way to implement a Dependency Injection Container in PHP. I’ve been confused by some containers which I believed are using the Service Locator pattern instead of dependency injection to fulfill Inversion of Control. And finally got my Interface Injection working… You’ve got no idea what I am writing about?

Inversion of Control
Before I start to explain things, I really recommend to read an article about Inversion of Control written by a person with way more knowledge than I do have. Wikipedia describes Inversion of Control as „design in which custom-written portions of a computer program receive the flow of control from a generic, reusable library“ and states that „software architecture with this design inverts control as compared to traditional procedural programming“ which means that „with inversion of control, it is the reusable code that calls into the custom, or task-specific, code“. I think that Inversion of Control is a difficult term because nowadays many refer to it and in fact simply talk about building object containers which does not necessarily inverses the control as the name suggests. That is why I do prefer the Hollywood principle as description for Inversion of Control: Don’t call us, we’ll call you!

Dependency Injection, Constructor-Injection, tight and loose coupling
With Inversion of Control you will end up at the terms Dependency Injection and Service Locator. Both define a way to achieve the above. For that to understand let me show an example without either and let me clarify what tight and loose coupling is about.

class XmlReader
{
}
 
class Configuration
{
    private $reader;
    public function __construct()
    {
        $this->reader = new XmlReader('some.xml');
    }
}
 
$config = new Configuration();

Here you do have what we call tight coupling (tight coupling between the Configuration object and the XmlReader object). In case you want to load your configuration parameters from a database or a simple text file you’ll need to edit the constructor of the configuration object. If you want to share your code you’ll need to share the XmlReader as well.

interface Reader
{
    /**
     * @param string $paramName
     * @return string
     */
    public function getParameter($paramName);
}
 
class XmlReader implements Reader
{
}
 
class Configuration
{
    private $reader;
    public function __construct(Reader $reader)
    {
        $this->reader = $reader;
    }
}
 
$reader = new XmlReader('some.xml');
$config = new Configuration($reader);

And this is an example for loose coupling, dependency injection concisely constructor injection. Let us start with loose coupling: It is loose coupling because you can easily replace XmlReader by DatabaseReader, TextReader, WhateverReader. It is dependency injection because the Configuration object has obviously XmlReader (or to be more correct an object of type Reader) as dependency. This dependency is injected into Configuration using the constructor and hence this is called constructor injection. What do we solve with this approach?

First of all, if you’d share the interface (which is something like a blueprint) with your neighbor, he/she knows that his/her own reader needs to implement a method called getParameter which accepts a string as parameter and will return a string. HOW his readers gets this data is irrelevant, whether it is from a file, a database or something else does not matter. You do not need to share your XmlReader object because you’ve decoupled it from your Configuration object. You can replace your XmlReader easily with mocks or stubs. Which means that testing gets easier.

Setter-Injection
The general difference between constructor injection and setter injection is that you are using a setter as the name suggests. So to re-use my example from above, it would look like this:

interface Reader
{
    /**
     * @param string $paramName
     * @return string
     */
    public function getParameter($paramName);
}
 
class XmlReader implements Reader
{
}
 
class Configuration
{
    private $reader;
    public function injectReader(Reader $reader)
    {
        $this->reader = $reader;
    }
}
 
$reader = new XmlReader('some.xml');
$config = new Configuration($reader);

I do prefix such methods with inject instead of set. I do prefer that because it shows that this has to do with injection and is not a parameter which you would set. But I guess thats a matter of taste. So, what makes setter injection special or better or worse than constructor injection? Personally I do think that this is a matter of taste as well. However, you might want to keep your constructor short. So if you have to inject 100 dependencies, setter injection might be favorable (ignoring the fact that you are doing something wrong if you do have 100 dependencies). I am trying to keep my constructors small and hence I am prefering setter injection over constructor injection. M. Fowler states that another „advantage with constructor initialization is that it allows you to clearly hide any fields that are immutable by simply not providing a setter.“ while that might be true I could as well do something like this

class Configuration
{
    private $reader = null;
    public function injectReader(Reader $reader)
    {
        if(is_null($this->reader))
            $this->reader = $reader;
    }
}

Which would make $reader immutable since it can only be injected if $reader is null – which won’t be the case once it got injected the first time. This has its downside as well as you might assume that a new object is initiated when you call injectReader twice. I’d however argue that this is a non-issue because for dependency injection you’d like objects which are always immutable. You may initiate an object again but not overwrite an existing. But again, that is just my personal opinion. He also states that „Constructors with parameters give you a clear statement of what it means to create a valid object in an obvious place.“ which shows the downside of using setter injection.

Assuming that you do need the reader in my example and it is not available because it hasn’t been injected you’re running into an error. Which means you have to be prepared for that situation by either using exceptions or by error’ing out nicely. That’s one thing more you need to take care of. Taking the pros and cons into mind I’d conclude that if you are able to divide your dependencies into hard (required) and soft (optional) dependencies, use constructor injection for the former and setter injection for the latter. Like so

class Configuration
{
    /**
     * @param Reader $reader is a hard dependency which is required for this to work
     */
    public function __construct(Reader $reader)
    {
        $this->reader = $reader;
    }
 
    /**
     * @param Validation $validation optional dependency which checks if all values are valid
     */
    public function injectValidation(Validation $validation)
    {
        $this->validation = $validation;
    }
}

Yes, it is arguable if validation is a required dependency or an optional one. But I guess you get what I am trying to show here.

Interface-Injection
Generally this type of injection is like setter injection with the addition of using an interface. This results in a lot of work because you’ll end up writing lots of interfaces. I do like interface injection, because the dependeny is pretty easy to spot and the interface acts as a contract telling your object what it needs to implement for the injection to work.

I do prefix such interfaces with „dependsOn“ which will make autowiring (later) simple (or probably SomeDependency which does read more nice: implements dependsOnRequest vs implements RequestDependency) and highlights that a given dependency is used. An example for that is here

class Database
{
}
 
class Response
{
}
 
class Request
{
}
 
interface dependsOnRequest
{
    public function injectRequest(Request $request);
}
 
interface dependsOnDatabase
{
    public function injectDatabase(Database $database);
}
 
interface dependsOnResponse
{
    public function injectResponse(Response $response);
}
 
class Router implements dependsOnRequest, dependsOnResponse
{
    private $request;
    private $response;
 
    public function injectRequest(Request $request)
    {
        $this->request = $request;
    }
 
    public function injectResponse(Response $response)
    {
        $this->response = $response;
    }
}

Traits
Taking the once and only once (OAOO) principle into account you might use traits to save some repeated code snippets. Then your flow would be:

1. create an interface which needs to be implemented by every class which needs the dependency

interface dependsOnRequest
{
    public function injectRequest(Request $request);
}

2. write a trait with the inject method which can be re-used by every class which needs the dependency

trait RequestInjector
{
    public function injectRequest(Request $request)
    {
        $this->request = $request;
    }
}

3. use both in the class which needs the dependency

class Router implements dependsOnRequest
{
    use RequestInjector;
}
 
$router = new Router();
$router->injectRequest(new Request());
var_dump($router);

which will output:

object(Router)#1 (1) {
  ["request"]=>
  object(Request)#2 (0) {
  }
}

containers

The real fun starts when we take a look at containers. For that to understand it makes sense to get the difference between a service locator and dependency injection. A container is basically an object which holds other objects/dependencies.

Service Locator
A simple service locator will have two methods, attach (or register, create, ..) and lookup (or get, find, ..) example:

class ServiceLocator
{
    private $services = array();
 
    public function attach($identifier, $service) 
    {
        $this->services[$identifier] = $service;
    }
 
    public function lookup($identifier)
    {
        return $this->services[$identifier];
    }
}
 
class Router
{
    private $request;
    private $response;
    public function __construct(ServiceLocator $locator)
    {
        $this->request = $locator->lookup('request');
        $this->response = $locator->lookup('response');
    }
}
 
$locator = new ServiceLocator();
$locator->attach('request', new Request);
$locator->attach('response', new Response);
$router = new Router($locator);

Instead of injecting tons of objects into your class, you could just inject the service locator and retrieve all your objects from the locator. This is just a simple example. The point here is: The object which NEEDS a dependency NEEDS to call for it. That is different from what dependency injection is about. Remember the hollywood principle? Don’t call us, we’ll call you! M. Fowler writes that with „injection there is no explicit request, the service appears in the application class – hence the inversion of control“.

PHP Dependency Injection Containers
It is time to take a look at some existing PHP DI Containers I think. This is no critism to those containers. Just pointing out how it does work with them. There is for example pimple which has the following example on their page:

// define some services
$container['session_storage'] = function ($c) {
    return new SessionStorage('SESSION_ID');
};
 
$container['session'] = function ($c) {
    return new Session($c['session_storage']);
};
 
// get the session object
$session = $container['session'];
 
// the above call is roughly equivalent to the following code:
// $storage = new SessionStorage('SESSION_ID');
// $session = new Session($storage);

Here you can see that pimple is a hybrid implementation (service locator and dependency injection) since you can retrieve the object by $container[‚identifier‘]. However, you can see that $c[’session_storage‘] is injected using constructor injection. Another variant of a service locator paired with dependency injection is Container. A nice example is on their page as well:

$container = new League\Container\Container;
 
// by registering the storage implementation as an alias of it's interface it
// is easy to swap out for other implementations
$container->add('Acme\Session\StorageInterface', 'Acme\Session\Storage');
 
$container
    ->add('Acme\Session\Session')
    ->withArgument('Acme\Session\StorageInterface')
    ->withArgument(new League\Container\Argument\RawArgument('my_super_secret_session_key'));
 
$session = $container->get('Acme\Session\Session');

Here you can see how Storage and Session are added to the service locator and how Storage is injected into session using constructor injection (->withArgument(‚Acme\Session\StorageInterface‘)). Same is true for a few other dependency injection containers in PHP. There’s PHP-DI which also uses a service locator at the root as the following example from their documentation shows.

$userManager = $container->get('UserManager');

They do state in their documentation „We don’t want to call the container everywhere in our application: it would couple our code to the container. This is known as the service locator antipattern – or dependency fetching rather than injection„.

Here it starts to become really interesting. For one I did learn that dependency injection and service locator are two different ways to achieve inversion of control. If you’re using some sort of framework which offers a service locator for all the dependencies and you’re only going to use your classes with that framework coupling between the code and the container is not a bad thing in my opinion. I wouldn’t call it a „service locator antipattern“ to be honest, because a service locator is not a bad thing. The right tool for the right job, remember? And another benefit from using such containers is that you do only have to inject one object (your service locator) instead of 100.

However, exactly this is where my headache begun. Whenever I did look at the various PHP DI Containers I’ve seen the service locator pattern and was like „wtf? that’s not dependency injection?“. I didn’t look close enough. Most have a mixture of both which is absolutely fine. But: Is it possible to create a dependency injection container without a service locator in PHP? I think Dice does so. Basically because there’s no getter to retrieve a service/dependency. You need to „wrap“ the object with dice which makes it possible for the injection to happen from the outside and which leads to autowiring on its own. An example in Dice looks like this:

use Dice\Dice;
 
require_once('Dice.php');
 
$dice = new Dice();
 
class Request {
}
 
class Router {
    public $request;
    public function __construct(Request $request) {
        $this->request = $request;
    }
}
 
$router = $dice->create('Router');
var_dump($router);

which results in

object(Router)#9 (1) {
  ["request"]=>
  object(Request)#8 (0) {
  }
}

Dice resolved the dependency on its own, which is called autowiring: I did not need to define anything on how or why or where Request needs to be injected into Router.

Continuing this in my next blog post.

No Comments

Post a Comment