Detailed Explanation of Automatic Dependency Injection Based on Reflection Mechanism in PHP

  • 2021-08-21 19:55:45
  • OfStack

In this paper, an example is given to illustrate the method of automatic dependency injection based on reflection mechanism in PHP. Share it for your reference, as follows:

Dependency injection, also known as inversion of control, should be familiar to anyone who has used the framework. Many people think it is a very tall thing when they look at the name, so they are discouraged from it. Today, they took time to study it and unlock its mysterious veil. Don't say much nonsense, go directly to the code;


/**
*
*  Utility class, which is used to implement automatic dependency injection. 
*
*/
class Ioc {
  //  Get an object instance of a class 
  public static function getInstance($className) {
    $paramArr = self::getMethodParams($className);
    return (new ReflectionClass($className))->newInstanceArgs($paramArr);
  }
  /**
   *  Execute the method of the class 
   * @param [type] $className [ Class name ]
   * @param [type] $methodName [ Method name ]
   * @param [type] $params   [ Additional parameters ]
   * @return [type]       [description]
   */
  public static function make($className, $methodName, $params = []) {
    //  Gets an instance of a class 
    $instance = self::getInstance($className);
    //  Get the parameters of dependency injection required by this method 
    $paramArr = self::getMethodParams($className, $methodName);
    return $instance->{$methodName}(...array_merge($paramArr, $params));
  }
  /**
   *  Get the method parameters of the class, and only get the typed parameters 
   * @param [type] $className  [description]
   * @param [type] $methodsName [description]
   * @return [type]       [description]
   */
  protected static function getMethodParams($className, $methodsName = '__construct') {
    //  Obtain this class by reflection 
    $class = new ReflectionClass($className);
    $paramArr = []; //  Record parameters, and parameter types 
    //  Determine whether the class has a constructor 
    if ($class->hasMethod($methodsName)) {
      //  Get the constructor 
      $construct = $class->getMethod($methodsName);
      //  Determine whether the constructor has parameters 
      $params = $construct->getParameters();
      if (count($params) > 0) {
        //  Determine the parameter type 
        foreach ($params as $key => $param) {
          if ($paramClass = $param->getClass()) {
            //  Get the parameter type name 
            $paramClassName = $paramClass->getName();
            //  Get the parameter type 
            $args = self::getMethodParams($paramClassName);
            $paramArr[] = (new ReflectionClass($paramClass->getName()))->newInstanceArgs($args);
          }
        }
      }
    }
    return $paramArr;
  }
}

The above code uses the reflection function of php to create a container class, which is used to implement the dependency injection function of other classes. The above dependency injection is divided into two types, one is the dependency injection of constructors and the other is the dependency injection of methods. Let's use the following three classes for the next test.


class A {
  protected $cObj;
  /**
   *  Used to test multilevel dependency injection  B Dependency A , A Dependency C
   * @param C $c [description]
   */
  public function __construct(C $c) {
    $this->cObj = $c;
  }
  public function aa() {
    echo 'this is A->test';
  }
  public function aac() {
    $this->cObj->cc();
  }
}
class B {
  protected $aObj;
  /**
   *  Test constructor dependency injection 
   * @param A $a [ Use lead injection A]
   */
  public function __construct(A $a) {
    $this->aObj = $a;
  }
  /**
   * [ Test method call dependency injection ]
   * @param C   $c [ Dependency injection C]
   * @param string $b [ This is a parameter that you fill in manually ]
   * @return [type]  [description]
   */
  public function bb(C $c, $b) {
    $c->cc();
    echo "\r\n";
    echo 'params:' . $b;
  }
  /**
   *  Verify that dependency injection is successful 
   * @return [type] [description]
   */
  public function bbb() {
    $this->aObj->aac();
  }
}
class C {
  public function cc() {
    echo 'this is C->cc';
  }
}

Dependency injection for test constructors


//  Use Ioc To create B Class, B Constructor dependency of A Class, A Constructor dependency of C Class. 
$bObj = Ioc::getInstance('B');
$bObj->bbb(); //  Output: this is C->cc  ,   Indicates that dependency injection is successful. 
//  Print $bObj
var_dump($bObj);
//  Print the result, as you can see B Among them A Example, A Among them C Example to illustrate the success of dependency injection. 
object(B)#3 (1) {
 ["aObj":protected]=>
 object(A)#7 (1) {
  ["cObj":protected]=>
  object(C)#10 (0) {
  }
 }
}

Test method dependency injection


Ioc::make('B', 'bb', ['this is param b']);
//  Output results, you can see that dependency injection is successful. 
this is C->cc
params:this is param b

From the above two examples, we can see that when we create an object or call a method, we don't have to know which class the class or the method depends on. Using reflection mechanism, we can easily inject the required classes automatically.

Summarize

Ok, is it easy to see the above code? In fact, as long as you are familiar with the reflection mechanism of php, Dependency injection is not difficult to achieve, the above code in order to facilitate understanding, so write simple anti-violence, in the actual project will definitely not be so simple, such as: will be injected into the class and parameters configuration, such as caching instantiated class, the next time you need an instance of this class, you can use it directly, without reinitializing, and so on. However, I believe that the principle is understood, and others can be improved according to the needs of the project.

For more readers interested in PHP related content, please check the topics on this site: "Introduction to php Object-Oriented Programming", "Introduction to PHP Basic Syntax", "Summary of PHP Operation and Operator Usage", "Summary of PHP Network Programming Skills", "Encyclopedia of PHP Array (Array) Operation Skills", "Summary of php String (string) Usage", "Introduction to php+mysql Database Operation Skills" and "Summary of php Common Database Operation Skills"

I hope this article is helpful to everyone's PHP programming.


Related articles: