php面试实现反射注入的详细方法分享!

PHP具有完整的反射API,提供了对类、接口、函数、方法和扩展进行逆向工程的能力。通过类的反射提供的能力我们能够知道类是如何被定义的,它有什么属性、什么方法、方法都有哪些参数,类文件的路径是什么等很重要的信息。正是因为类的反射,很多PHP框架才能实现依赖注入自动解决类与类之间的依赖关系,这给我们平时的开发带来了很大的方便。

本文主要是讲解如何利用类的反射来实现依赖注入(Dependency Injection),并不会去逐条讲述PHP Reflection里的每一个API。为了更好地理解,我们通过一个例子来看类的反射,以及如何实现依赖注入。

下面这个类代表了坐标系里的一个点,有两个属性横坐标x和纵坐标y。

  /**     * Class Point     */    class Point    {     public $x;     public $y;          /**     * Point constructor.     * @param int $x horizontal value of point's coordinate     * @param int $y vertical value of point's coordinate     */     public function __construct($x = 0, $y = 0)     {     $this->x = $x;     $this->y = $y;     }    }

接下来这个类代表圆形,可以看到在它的构造函数里有一个参数是Point类的,即Circle类是依赖与Point类的。

  class Circle    {     /**     * @var int     */     public $radius;//半径          /**     * @var Point     */     public $center;//圆心点          const PI = 3.14;          public function __construct(Point $point, $radius = 1)     {     $this->center = $point;     $this->radius = $radius;     }          //打印圆点的坐标     public function printCenter()     {     printf('center coordinate is (%d, %d)', $this->center->x, $this->center->y);     }          //计算圆形的面积     public function area()     {     return 3.14 * pow($this->radius, 2);     }    }

ReflectionClass

下面我们通过反射来对Circle这个类进行反向工程。把Circle类的免费精选名字大全传递给reflectionClass来实例化一个ReflectionClass类的对象。

  $reflectionClass = new reflectionClass(Circle::class);    //返回值如下    object(ReflectionClass)#1 (1) {     ["name"]=>     string(6) "Circle"    }

反射出类的常量

  $reflectionClass->getConstants();

返回一个由常量名称和值构成的关联数组

  array(1) {     ["PI"]=>     float(3.14)    }

通过反射获取属性

  $reflectionClass->getProperties();

返回一个由ReflectionProperty对象构成的数组

  array(3) {     [0]=>     object(ReflectionMethod)#2 (2) {     ["name"]=>     string(11) "__construct"     ["class"]=>     string(6) "Circle"     }     [1]=>     object(ReflectionMethod)#3 (2) {     ["name"]=>     string(11) "printCenter"     ["class"]=>     string(6) "Circle"     }     [2]=>     object(ReflectionMethod)#4 (2) {     ["name"]=>     string(4) "area"     ["class"]=>     string(6) "Circle"     }    }

我们还可以通过getConstructor()来单独获取类的构造方法,其返回值为一个ReflectionMethod对象。

  $constructor = $reflectionClass->getConstructor();

反射出方法的参数

  $parameters = $constructor->getParameters();

其返回值为ReflectionParameter对象构成的数组。

  array(2) {     [0]=>     object(ReflectionParameter)#3 (1) {     ["name"]=>     string(5) "point"     }     [1]=>     object(ReflectionParameter)#4 (1) {     ["name"]=>     string(6) "radius"     }    }

依赖注入

好了接下来我们编写一个名为make的函数,传递类名称给make函数返回类的对象,在make里它会帮我们注入类的依赖,即在本例中帮我们注入Point对象给Circle类的构造方法。

  //构建类的对象    function make($className)    {     $reflectionClass = new ReflectionClass($className);     $constructor = $reflectionClass->getConstructor();     $parameters = $constructor->getParameters();     $dependencies = getDependencies($parameters);           return $reflectionClass->newInstanceArgs($dependencies);    }         //依赖解析    function getDependencies($parameters)    {     $dependencies = [];     foreach($parameters as $parameter) {      $dependency = $parameter->getClass();      if (is_null($dependency)) {       if($parameter->isDefaultValueAvailable()) {        $dependencies[] = $parameter->getDefaultValue();       } else {        //不是可选参数的为了简单直接赋值为字符串0        //针对构造方法的必须参数这个情况        //laravel是通过service provider注册closure到IocContainer,        //在closure里可以通过return new Class($param1, $param2)来返回类的实例        //然后在make时回调这个closure即可解析出对象        //具体细节我会在另一篇文章里面描述        $dependencies[] = '0';       }      } else {       //递归解析出依赖类的对象       $dependencies[] = make($parameter->getClass()->name);      }     }          return $dependencies;    }

本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

ctvol管理联系方式QQ:251552304

本文章地址:https://www.ctvol.com/phpttorial/470337.html

(0)
上一篇 2020年10月26日
下一篇 2020年10月26日

精彩推荐