News Archive
PhpRiot Newsletter
Your Email Address:

More information

Dependency Injection Container Refactorings, Part One

Note: This article was originally published at Planet PHP on 20 April 2011.
Planet PHP

(c) Jil A. Brown

Working heavily with the Symfony2 Dependency Injection Container, I feel that we found some typical refactorings towards a DI container that emerge during the introduction of such a component. I want to write down the preliminary results of trying to systematize more or less as a draft. I will use the Symfony2 DI container configuration as an example but most of the refactorings should be applicable to other containers as well, some of them even to dependency injection without a container.

Make Dependency Explicit

This is typically the first step towards Dependency Injection: make a dependency explicit. There are three typical ways to do so, first is constructor injection, second is setter injection and third and less preferred is property injection. I roughly prefer constructor injection for invariant dependency in my domain and setter injection for infrastructure (setNotifier e.g.). Consider this example:

execute(); } }

Client creates a new instance of Dependency and call execute(). Bad for testing and for configuration, Dependency will always be hard coded there. To make it easier manageable we refactor towards setter injection:

_dependency = $dependency; } a public function execute() { $this-_dependency-execute(); } }

Now we can manage Client in the DI container like this:

We see that the dependency is explicit: we specifically configure Example\Client and pass a specific Example\Dependency object.

Introduce Interface Injection

After a number of Explicit Dependency refactorings our configuration file for the service container will become huge. We will notice that we have common dependencies that are used at various places, an event manager for example. To fix that rapid growth we choose to utilize Interface Injection to ease configuration.

This is the configuration starting point:

We notice that both Example\Client and Example\AnotherClient depend on Example\Dependency. First of all we need an interface contracting setDependency. This is basically the Extract Interface refactoring. We call the newly extracted interface Example\DependencyAware.

The interface:

And we refactor both Example\Client and Example\AnotherClient to implement Example\DependencyAware.

Now we change our configuration to call setDependency no longer explicitly for Example\Client and Example\AnotherClient but for every object implementing Example\DependencyAware.


Truncated by Planet PHP, read more at the original (another 2290 bytes)