preface

For PHP frameworks, whether they are Yichi, Symfony or Laravel, everyone has been working on them. The vendor folder and the entry file (index. PHP or app. PHP) that reside in the framework are also met daily. But are you really familiar with these files/folders? How does a complete project evolve from a clean framework? What is the role of each part in the framework of the building?

Dependency Injection

Dependency injection is not SQL injection O (ヘ ̄ O #)

1.1 Describe the relationship between dependency injection and reflection classes

When it comes to DI, 90% of the articles mention something called Reflection, which leads many observers (including me) to think that both are one and the same, when in fact they are two very different concepts. Reflection is a Reflection class, it’s a dependency injection DI is a design pattern, how can Reflection classes and design patterns be the same thing? So their relationship is dependency — that is, dependency injection is a design pattern that relies on reflection classes.

1.2 What is Reflection

Write A very simple class A with A single object $A and A single method A ().

class A { public $a; public function a() { echo __FUNCTION__; }}

Then we start calling the Reflection class Reflection

$A = new A(); $reflect = new ReflectionObject($A); $props = $reflect->getProperties(); // Get all objects of this class...

We know everything we need to know about a class through reflection, almost like an X-ray to get all the details of a class. However, after I finished the reflection class, I was lost again. What is the purpose of this reflection class? If you want to know how many methods/objects are in the original class, you can just look at the original class. Why bother? What does this have to do with Dependency Injection? Don’t worry, let’s talk about something else first and then come back to it.

1.3 What should we do if we are all dependent

Now I have A scenario where I want to instantiate B, but B depends on A. How do you do that? It is very simple and can be solved as follows.

Class A{// do STH.} Class B{public function __construct(A $A){// struct $A = new A(); $b = new B($a);

Simple, right? It can be solved in two strokes. There is nothing difficult about it. But if you now have A situation where there are 26 classes from A to Z, B depends on A, C depends on B, and so on. So if I want to instantiate class Z, what do you have to do? Do you still use the method shown above? Wouldn’t it take 26 lines to instantiate Z?

So is there a way to instantiate B directly and then load all the other classes in automatically? Also is there. I’m going to use the reflection class that I just showed you.

<? PHP /** * utility class, used to implement automatic dependency injection. Public static function getInstance($className) {$paramArr = "{$className =" self::getMethodParams($className); return (new ReflectionClass($className))->newInstanceArgs($paramArr); } /** * Returns the method parameters of the class, and only the parameters with type. * @Param [type] $className [className] * @Param [type] $className [method name] * @Return [mixed] */ protected static function getMethodParams($className, $methodsName = '__construct') {$class = new ReflectionClass($className); $paramArr = []; // log parameters, If ($class->hasMethod($methodsName)) {$construct = $class->getMethod($methodsName); if ($methodsName) {$construct = $class->getMethod($methodsName); $params = $construct->getParameters(); $construct->getParameters(); If (count($params) > 0) {foreach ($params as $key => $param) {if ($params as $key => $param) {$paramClass = $param->getClass()) $paramClassName = $paramClass->getName(); $args = self::getMethodParams($args); $args = self::getMethodParams($args); $paramArr[] = (new ReflectionClass($paramClass->getName()))->newInstanceArgs($args); } } } } return $paramArr; } /** * Executes the method of the class * @Param [type] $className [className] * @Param [type] $className [methodName] * @Param [type] $className [methodName] * @Param [type] $className [methodName] * @Param [type] $params [extra parameter] * @return [type] [description] */ public static function make($className, $methodName, $instance = self::getInstance($className); $className = self::getInstance($className); $paramArr = self::getMethodParams($className, $methodName); return $instance->{$methodName}(... array_merge($paramArr, $params)); } } class A { // ... } class B { public function __construct(A $a) { // ... } } class C { public function __construct(B $b) { // ... } } $cObj = Ioc::getInstance('C');

Let’s focus on the IoC class’s getMethodParams method.

Let’s talk about the general situation: this method is to use recursion through the loaded classes to load all the dependent classes in the purpose.

This method first instantiates Reflection, then uses the getMethod method to get the __construct method of the loaded class, and then sees if there are any other classes in the __construct as arguments. If so, the process is repeated recursively until there are no dependencies.

This is a simple example of dependency injection using Reflection. It’s a little more complicated in the actual framework than the example above, but it’s still pretty much the same.

For example, many frameworks use a concept called container — use $this->getContainer()->get(YOUR_CLASS_NAME) to get a class. What kind of high-tech thing is this container? Don’t worry, it comes down to dependency injection.

We’ll take a closer look at how Symfony’s container is designed.