Today’s post have a very long title, even though the actual concept we are going to discuss is quite simple and straightforward. The whole concept of dependency injection can sound very complicated, but it really isn’t.

This is dependency injection:

class UserManager
{
    protected $users;

    public function __construct(UserRepository $users)
    {
        $this->users = $user;
    }
}

The UserManager depends on a UserRepository, which we therefore inject through the constructor. This has some obvious advantages – especially if we make our objects dependent on interfaces instead of implementations. We will get back to this in part 2.

Resolving dependencies

How do we resolve the dependencies of our objects, so we can properly instantiate them? This can be quite cumbersome.

Instantiating an object with its dependencies:

$userManager = new UserManager(
    new UserRepository(
        new EntityMapper(
            new DB(
                new Configuration()
))));

You get the point. The dependencies has dependencies themselves.

We need to automate this, and actually, automatic dependency resolution is a core part of modern PHP frameworks such as Laravel. Lately, though, I have been working on several legacy codebases (I consider WordPress legacy as well), where some sort of automatic resolution comes in very handy. In legacy projects, oftentimes there is no easy way to access different objects across the codebase (global variables, I’m looking at you!). Implementing some sort of service container that can help me resolve services and their dependencies is always one of the first things I do. And the good news is, with PHP’s reflection API, this is not too hard to implement.

Here is what the PHP documentation says about reflection:

PHP 5 comes with a complete reflection API that adds the ability to reverse-engineer classes, interfaces, functions, methods and extensions.

In short, the reflection API gives us an easy way to gather information about our classes and objects (including their dependencies), which is exactly what we need to implement our own dependency resolution mechanism.

Ultimately, this is what we want:

$userManager = $container->resolve('UserManager');
// UserManager instance, including all nested dependencies

Let’s see some code:

class Container
{
    public function resolve($class)
    {
        // Reflect on the $class
        $reflectionClass = new ReflectionClass($class);

        // Fetch the constructor (instance of ReflectionMethod)
        $constructor = $reflectionClass->getConstructor();

        // If there is no constructor, there is no
        // dependencies, which means that our job is done.
        if ( ! $constructor)
            return new $class;

        // Fetch the arguments from the constructor
        // (collection of ReflectionParameter instances)
        $params = $constructor->getParameters();

        // If there is a constructor, but no dependencies,
        // our job is done.
        if (count($params) === 0)
            return new $class;

        // This is were we store the dependencies
        $newInstanceParams = [];

        // Loop over the constructor arguments
        foreach ($params as $param) {

            // Here we should perform a bunch of checks, such as:
            // isArray(), isCallable(), isDefaultValueAvailable()
            // isOptional() etc.

            // For now, we just check to see if the argument is
            // a class, so we can instantiate it,
            // otherwise we just pass null.
            if (is_null($param->getClass())) {
                $newInstanceParams[] = null;
                continue;
            }


            // This is where 'the magic happens'. We resolve each
            // of the dependencies, by recursively calling the
            // resolve() method.
            // At one point, we will reach the bottom of the
            // nested dependencies we need in order to instantiate
            // the class.
            $newInstanceParams[] = $this->resolve(
                $param->getClass()->getName()
            );
        }

        // Return the reflected class, instantiated with all its
        // dependencies (this happens once for all the
        // nested dependencies).
        return $reflectionClass->newInstanceArgs(
            $newInstanceParams
        );
    }
}

With the resolve() method, we can achieve something like this:

php > $userManager = $container->resolve('UserManager');
php > var_dump($userManager);
class UserManager#7 (1) {
  protected $users =>
  class UserRepository#10 (1) {
    protected $em =>
    class EntityMapper#13 (1) {
      protected $db =>
      class DB#14 (1) {
        ...
      }
    }
  }
}

This works because of the recursive behaviour of the method. According to Wikipedia, recursion:

… refers to a method of defining functions in which the function being defined is applied within its own definition.

The above definition basically means that a function calls itself. In our case, the resolve() method calls itself with each dependency it discovers as a parameter. We do not want dependencies to depend on each other, in which case we would have a recursive loop that would never end. Object #1 would require object #2 that would require object #1 and so on. Dependencies should only go one way, so we know that our recursive dependency resolution mechanism will eventually hit the bottom of the dependency tree.

That was a lot of fancy words for a simple concept, but I hope you get the idea. The PHP reflection API is fun to play around with and indeed very useful. In the next part, we will take a look at how to allow binding of actual implementations to the service container, so our code can rely on interfaces instead.

  1. This is a very helpful article. Wonderfully explained. Thanks

    Reply

  2. Waiting for the part 2

    Reply

Leave a Reply

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