In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-03-28 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
This article mainly explains "how to create a PHP DI container". The content of the article is simple and clear, and it is easy to learn and understand. Please follow the editor's ideas to study and learn "how to create a PHP DI container".
Start by driving
Let's drive a car and give us a chestnut:
Class Driver {public function drive () {$car = new Car (); echo 'old driver is driving', $car- > getCar (), PHP_EOL;}} class Car {protected $name = 'regular car'; public function getCar () {return $this- > name;}}
There are two classes, Driver and Car. Driver, the veteran driver, has a method driver, which requires the whole car $car first and then leaves. Most students have written such or similar code, this kind of code is not wrong, it's normal. However, if I want to change my car, I can't get a girl in a regular car.
Class Benz extends Car {protected $name = 'Mercedes Benz';}
At this time, you need to do a more disgusting operation, you have to change the old driver's code. (old driver: what did I do wrong? I have to relearn my driver's license to change my car. ). So we need to inject Car into the outside world and decouple Driver from Car, so that old drivers don't have to build their own cars when they drive. So there is the following result
Class Driver {protected $car; public function _ construct (Car $car) {$this- > car = $car;} public function drive () {echo 'Old driver is driving', $this- > car- > getCar (), PHP_EOL;}}
At this point, the Driver and Car classes have been decoupled, and the dependencies of these two classes are managed by the upper code. At this point, the old driver will "drive" like this:
$car = new Car (); $driver = new Driver ($car); $driver- > drive ()
At this point, we create an instance of the Driver dependency and inject it. In the above example, we have implemented dependency injection, but it is manual, and it still feels uncomfortable to write. How can such heavy work be done manually? you have to let the program do it on its own. As a result, DI containers were born.
Dependency injection container
Dependency injection, similar to the IoC pattern, is a pattern that solves the dependency coupling relationship between callers and callees. It solves the dependency relationship between objects, makes objects only rely on the IoC/DI container, no longer directly depends on each other, and realizes loose coupling, and then when the object is created, the IoC/DI container injects its Dependency objects into it (Inject), which can achieve loose coupling to the maximum extent. Dependency injection, to put it bluntly, is that the container injects instances of other classes that a class depends on into instances of that class.
This paragraph may be a little abstract, let's go back to the example just now. I just finished dependency injection manually, which is troublesome, which must be tedious and not elegant enough for a large project. So we need a manager to do this instead of us, and this manager is the container. The dependency management of the class is left to the container. Therefore, generally speaking, the container is a global object that everyone has in common.
Make your own DI container
To write a function, we first need to analyze the problem, so we need to understand what functions are needed for a simple DI container, which is directly related to the writing of our code. For a simple container, at least the following points need to be met:
Create an instance of the desired class
Complete dependency Management (DI)
You can get an instance of a singleton
Globally unique
To sum up, our container class looks something like this:
Class Container {/ * singleton * @ var Container * / protected static $instance; / * instance managed by the container * @ var array * / protected $instances = [] Private function _ _ construct () {} private function _ _ clone () {} / * * get the singleton instance * @ param string $class * @ param array... $params * @ return object * / public function singleton ($class . $params) {} / * get an instance (create a new one each time) * @ param string $class * @ param array. $params * @ return object * / public function get ($class,. $params) {} / * * Factory method Create an instance and complete dependency injection * @ param string $class * @ param array $params * @ return object * / protected function make ($class, $params = []) {} / * * @ return Container * / public static function getInstance () {if (null = static::$instance) {static::$instance = new static () } return static::$instance;}}
Now that the general skeleton has been determined, let's move on to the core make method:
Protected function make ($class, $params = []) {/ / if it's not a reflective class, create $class = is_string ($class) based on the class name? New ReflectionClass ($class): $class; / / if the input parameter is not empty, create an instance if (! empty ($params)) {return $class- > newInstanceArgs ($params) based on the input parameter;} / / get the constructor $constructor = $class- > getConstructor (); / / get the constructor parameter $parameterClasses = $constructor? $constructor- > getParameters (): [] If (empty ($parameterClasses)) {/ / if the constructor has no input, directly create return $class- > newInstance ();} else {/ / if the constructor has input, iterate and recursively create a dependency class instance foreach ($parameterClasses as $parameterClass) {$paramClass = $parameterClass- > getClass (); $params [] = $this- > make ($paramClass) } / / finally, create the instance based on the created parameters, and complete the dependent injection return $class- > newInstanceArgs ($params);}}
In order to make the container easy to use, I made some improvements:
Implement the ArrayAccess interface so that the singleton instance can be obtained directly through array. If the instance does not exist, create
Override the _ _ get method for easier access to
Final version:
Class Container implements ArrayAccess {/ * singleton * @ var Container * / protected static $instance; / * instance managed by the container * @ var array * / protected $instances = [] Private function _ _ construct () {} private function _ _ clone () {} / * get the singleton instance * @ param string $class * @ param array... $params * @ return object * / public function singleton ($class,... $params) {if (isset ($this- > instances [$class])) {return $this- > instances [$class] } else {$this- > instances [$class] = $this- > make ($class, $params);} return $this- > instances [$class] } / * get an instance (create a new one each time) * @ param string $class * @ param array... $params * @ return object * / public function get ($class,... $params) {return $this- > make ($class, $params) } / * factory method, create an instance, and complete dependency injection * @ param string $class * @ param array $params * @ return object * / protected function make ($class, $params = []) {/ / if it is not a reflective class to create $class = is_string ($class) based on the class name? New ReflectionClass ($class): $class; / / if the input parameter is not empty, create an instance if (! empty ($params)) {return $class- > newInstanceArgs ($params) based on the input parameter;} / / get the constructor $constructor = $class- > getConstructor (); / / get the constructor parameter $parameterClasses = $constructor? $constructor- > getParameters (): [] If (empty ($parameterClasses)) {/ / if the constructor has no input, directly create return $class- > newInstance ();} else {/ / if the constructor has an input, iterate and recursively create a dependency class instance foreach ($parameterClasses as $parameterClass) {$paramClass = $parameterClass- > getClass () $params [] = $this- > make ($paramClass);} / / finally create an instance based on the created parameters, and complete the dependent injection return $class- > newInstanceArgs ($params) }} / * * @ return Container * / public static function getInstance () {if (null = static::$instance) {static::$instance = new static ();} return static::$instance } public function _ _ get ($class) {if (! isset ($this- > instances [$class])) {$this- > instances [$class] = $this- > make ($class);} return $this- > instances [$class];} public function offsetExists ($offset) {return isset ($this- > instances [$offset]) } public function offsetGet ($offset) {if (! isset ($this- > instances [$offset])) {$this- > instances [$offset] = $this- > make ($offset);} return $this- > instances [$offset];} public function offsetSet ($offset, $value) {} public function offsetUnset ($offset) {unset ($this- > instances [$offset]);}}
Now with the help of the container, let's write the above code:
$driver = $app- > get (Driver::class); $driver- > drive (); / / output: the veteran driver is driving a regular car to copy the code
It's as simple as that, the old driver can start the car. The default injection here is the instance of Car. If you need to drive a Mercedes-Benz, you only need to do this:
$benz = $app- > get (Benz::class); $driver = $app- > get (Driver::class, $benz); $driver- > drive (); / / output: the veteran driver is driving a Mercedes-Benz copy code
According to the requirements of PSR-11, the dependency injection container needs to implement the Psr\ Container\ ContainerInterface interface, which is not implemented in the demonstration here, because it requires the introduction of Psr dependency library, which is troublesome and simple, just a few more methods. If you are interested, you can learn about the requirements of PSR-11 (portal).
This is just a very simple DI container, which needs a lot of consideration in practice, and the function of the container here is still very simple. There are still some pits that have not been dealt with, such as the mechanism of how to deal with circular dependencies and delayed loading.
Thank you for your reading, the above is the content of "how to create a PHP DI container". After the study of this article, I believe you have a deeper understanding of how to create a PHP DI container, and the specific use needs to be verified in practice. Here is, the editor will push for you more related knowledge points of the article, welcome to follow!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.