I am getting my head around DI
and IoC
; using Pimple for now. Lets say I have my IoC defined early in the execution flow
$container = new Injection\Container();
$container['config'] = function ($c) {
return new Config($c['loader']);
};
$container['request'] = function ($c) {
return new Request($c['config']);
};
...
And a router class that call_user_func_array
//$class = 'Dog', $method = 'woof', $this->args = ['foo', 'bar']
call_user_func_array(array(new $class, $method), $this->args);
So new object is instantiated without being aware of the IoC
but still I would like to reuse some of the services defined.
class Dog
{
public function woof($var1, $var2)
{
//$request = IoC service here
}
}
My question is:
IoC
to the class (static seems to be evil...) orRead some nice articles, however was not able to figure it out
IoC
Containers and Dependency InjectionThe evil way I did that was defining another service that saves the IoC
in a static property
$container['services'] = function ($c) {
return Services::create($c); //make the service
};
$container['services']; //call the service
and access it later in the
class Dog
{
public function woof($var1, $var2)
{
$services = new Services();
$request = $services['request']; //retrieving the request service
}
}
Decided to use the least harmful way
//passing the container here
call_user_func_array(array(new $class($container), $method), $this->args);
And store the parameter in __constructor
public $container;
public function __construct(Injection\Container $container)
{
$this->container = $container;
}
The IoC container that is also known as a DI Container is a framework for implementing automatic dependency injection very effectively. It manages the complete object creation and its lifetime, as well as it also injects the dependencies into the classes.
An IoC container is a common characteristic of frameworks that implement IoC. In the Spring framework, the interface ApplicationContext represents the IoC container. The Spring container is responsible for instantiating, configuring and assembling objects known as beans, as well as managing their life cycles.
ApplicationContext interfaces acts as the IoC container.
Spring IoC Container is the core of Spring Framework. It creates the objects, configures and assembles their dependencies, manages their entire life cycle. The Container uses Dependency Injection(DI) to manage the components that make up the application.
There are 2 patterns that are commonly in use for IoC, and proponents for both.
However, it seems that more and more DI is winning out over the Service Locator pattern. Many DI containers are making it more difficult to use Service Locator and have warnings in the documentation not to go down that road.
In DI, you never pass the container to a class unless that class is part of the composition root. The composition root starts everything in motion by resolving the object graph at the entry point of the application, and from there on the application is entirely unaware of the DI container (has no reference to it). Note that this object graph may contain Abstract Factories that create runtime instances of classes (either by injecting a function to resolve from the DI container or simply by newing them up).
Service Locator is the other end of the spectrum. Typically the container is either made static or passed to a class as the only dependency. It might be easier to build classes this way, but you pay the price later when you actually have to configure the DI container.
With DI, the dependencies of a class are explicit so you need not look further than the constructor parameters. With Service Locator, configuring dependencies is much more complicated. This is the main reason (there are actually many reasons) why in recent years it is considered an anti-pattern.
So, to answer your question, if you want to follow the modern approach to IoC, don't pass the IoC container into the application. Instead, use a composition root at the entry point of your application to configure the container and build the object graph.
A complete example in PHP can be seen here. I found that page in a discussion on the Pimple project.
So, given your example:
class Dog
{
public function woof($var1, $var2)
{
//$request = IoC service here
}
}
You would need to add a constructor to accept your $request service so your class will receive an instance of it.
class Dog
{
protected $request;
public function __construct(Request $request)
{
$this->request = $request;
}
public function woof($var1, $var2)
{
//Use $request here, disregard the IoC container
$this->request->doSomething()
}
}
And then you would have a section where you define controllers in your composition root. This is where the dependencies are injected.
$container = new Injection\Container();
$container['config'] = function ($c) {
return new Config($c['loader']);
};
$container['request'] = function ($c) {
return new Request($c['config']);
};
$container['dog'] = $container->factory(function ($c) {
return new Dog($c['request']);
});
$container['user_controller'] = $container->share(function ($container) {
return new UserController(
$container['dog'] //,
// $container['someOtherDependency']
);
});
As you can see, using this approach your Dog
class is completely unaware of the DI container.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With