What is DI?
Dependency Injection is a software design pattern that implements
Inversion of control by decoupling software modules, introduced by
Martin Fowler.
Usually a dependency injection container is used to manage and automate the construction and lifetimes of interdependent objects.
Design pattern explanation and Use
Basically, if your class needs an object of other class, in this pattern you pass the dependency object as a constructor parameter or via property setters, instead of invoke factory or create dependency. You make it someone else’s problem.
Example 1:
class MyClass {
private $objectA;
public function __construct(ObjectA $object) {
$this->objectA = $object;
}
}
Example 2:
class MyClass {
private $objectA;
public function setObjectA(ObjectA $object) {
$this->objectA = $object;
}
}
In both examples, we don’t care how or where to create the objectA we just use it.
Some popular PHP DI-Container implementations
- PHP-DI: is an interesting implementation of DI Container that has integration with several frameworks and IDEs like PHPStorm.
- Symfony DependencyInjection: The DependencyInjection component allows you to standardize and centralize the way objects are constructed in your application.
- Zend – DI: DI Container implementation for Zend framwork.
- Pimple: Is a Dependency Injection Container from SensioLabs.
Pimple Presentation
This is an implementation from SensioLabs, and you guessed it, the same guys that created the Symfony libraries.
This is a friendly implemented package, lightweight and easy to use.
To install you just need to add to your composer.json,
$ ./composer.phar require pimple/pimple ~3.0
and you’re ready to use it!
$container = new \Pimple\Container();
Since it implements \ArrayAccess interface, you can store variables and factories as it was an array.
example of parameters:
$container['cookie_name'] = 'SESSION_ID';
an example of factory as a closure:
$container['session'] = $container->factory(function($c) {
return new Session($c['session_storage']);
});
It also provides methods to protect parameters, modify services after defined, extends, and more.
Example Use Cases
Let’s imagine that we want to create factories dynamically based on a JSON configuration like this:
Then we can create a Trait with a method that will fill our container based on an argument that could be an array create from the decode of above JSON.
Here’s how we can use this trait:
Let’s break down the example above:
the class that implements the __construct method has defined a member attribute, container, that is an instance of Pimple.
Since we are using traits to buildAuthenticator, the result of the foreach block will be assigned into the class container attribute.
Within the build, we need to create a new temporary Pimple object. This is a hack I found to store nested containers.
This is needed because otherwise each time you attempt to add a sub-item within the “AUTHENTICATION” it overrides the previous one.
So once we have created all factories, we just set the temporal container in “AUTHENTICATION” cell of the main container.
To use your created object in the container you just need to do something like that:
$auth = $this->container["AUTHENTICATION"]["mock"];
$result = $auth->doSomething();
Final Thoughts
This pattern is very useful and widely used these days especially in modern web development, in particular if you see it used in the Angular framework.
Even when you should pick the product that better match your requirements in each case, I can say that I feel very comfortable with Pimple. As I showed, it is very flexible, allowing you to create your own wrap class to customize its behavior and fit your needs.
Hope you enjoyed! Thanks for reading and see you on next posts!