Understanding of Dependency Injection Container
Coupling
A good code structure design must be loosely coupled, which is also the purpose of many common design patterns. It is to bring together the codes of the same function scattered everywhere to form a module, and then communicate between different modules through some small and clear channels.
In practice, the interdependence between different functions and modules is inevitable, and how to handle the relationship between these dependencies is the key to whether the code structure can become beautiful.
<?php class User { public function register($user) { // 注册操作 ... // 发送确认邮件 $notify = new Notify(); $notify->sendEmail('register', $user); } } class Notify { public function sendEmail($type, $data) { switch $type { case 'register': // 发送注册确认邮件 $email = new Email($type); $email->send($data); ... } } } class Email { public function send($data) { // 发送邮件 } }
In the above code, there are layer-by-layer dependencies between the three classes. The order of instantiation of the three classes is User -> Notify -> Email
That is to say, I instantiate first The User class may execute some code and then instantiate other classes I need, such as Notify, and so on.
This kind of dependency will force us to do some preparation work in order to get the required dependencies. Sometimes a new operation may not be enough. This part of the work is called coupling, which forces a class with independent functions to care about some operations that have nothing to do with its main function.
Removing the dependence of one class on other classes
It is also very simple to solve this problem. I can first instantiate the Email class, then instantiate Notify, and then pass the Email object as a parameter. To Notify, finally instantiate the User class, and then pass Notify in. This is the so-called dependency injection. You can see that the order of class instantiation in this process is completely reversed. The dependent object is instantiated first, rather than the final required object first. This is inversion of control.
The code is as follows:
<?php $email = new Email(); $notify = new Notify($email); $user = new User($notify);
You can inject the required dependencies through the constructor, or you can use some other methods.
Use containers to host dependencies
Then there is a new problem. There are only three classes in the example, but if the User class relies on Notify to send emails, it depends on Model stores the database and relies on redis for caching. Although this transfers the dependency outside the class, it still causes me to do a lot of manual preparation work when I just want to instantiate User, which makes the code confusing. So a container is needed at this time. The role of this container is to manage these dependencies for me.
<?php // 容器 class Container implements ArrayAccess { protected $values = []; public function offsetGet($offset) { return $this->values[$offset]($this); } public function offsetSet($offset, $value) { $this->values[$offset] = $value; } }
When the program starts, we can register a series of basic services in one place.
<?php $container = new Container(); $container['notify'] = function($c) { return new Notify(); }; $container['email'] = function($c) { return new Email(); };
It will become like this That is, when User needs Notify, he will ask the container for an object of this class. As for what other things Notify depends on, I don’t have to worry about it. , because Notify will also ask the container for the dependencies it needs. The processing of all these dependencies is completely managed by the container. We neither need to care about the hierarchical relationship between dependencies nor avoid the coupling between dependencies. It should be noted that the dependency injection container generally only accepts an anonymous function, not an instantiated object. The anonymous function will tell the container how to obtain an object, so that a service can be used when needed. It will be instantiated only when The above is the detailed content of Easy to understand PHP dependency injection container. For more information, please follow other related articles on the PHP Chinese website!<?php
class User
{
public function register($user)
{
// 注册操作
...
// 发送确认邮件
$container('notify')->sendEmail('register', $user);
}
}
class Notify
{
public function sendEmail($type, $data)
{
switch $type {
case 'register':
// 发送注册确认邮件
$email = $container['email'];
$email->send($data);
...
}
}
}
class Email
{
public function send($data)
{
// 发送邮件
}
}