Laravel内核分析-PHP反射和依赖注入

PHP 类的反射和依赖注入

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

为了更好地理解,我们通过一个例子来看类的反射,以及如何实现依赖注入。
下面这个类代表了坐标系里的一个点,有两个属性横坐标 x 和纵坐标 y。

<?php

namespace App\Http\Services\Model;

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 类的。

<?php

namespace App\Http\Services\Model;

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;
    }

    /**
     * Notes:打印圆点的坐标
     * User: '林如信'
     * DateTime: 2023/4/15 16:01
     */
    public function printCenter()
    {
        printf('center coordinate is (%d, %d)', $this->center->x, $this->center->y);
    }

    /**
     * Notes:计算圆形的面积
     * User: '林如信'
     * DateTime: 2023/4/15 16:01
     * @return float
     */
    public function area()
    {
        return self::PI * pow($this->radius, 2);
    }
}

ReflectionClass

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

public function reflection()
    {
        $reflectionClass = new reflectionClass(Circle::class);
        dd($reflectionClass);
    }

返回值如下

 

 

反射出类的常量

$reflectionClass = new reflectionClass(Circle::class);
dd($reflectionClass->getConstants());

返回值如下

 

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

通过反射获取属性

$reflectionClass = new reflectionClass(Circle::class);
dd($reflectionClass->getProperties());

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

 

 

反射出类中定义的方法

 

$reflectionClass = new reflectionClass(Circle::class);
dd($reflectionClass->getMethods());

 

 

返回 ReflectionMethod 对象构成的数组

 

还有很多种用法,都在文档里面有提到 官方文档

依赖注入

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

    /**
     * Notes:构建类的对象
     * User: '林如信'
     * DateTime: 2023/4/15 17:48
     * @param $className '类名(带路径)'
     * @return mixed
     */
    public function make($className)
    {
        //实例化反射类
        $reflectionClass = new ReflectionClass($className);
        //获取反射类的构造方法
        $constructor = $reflectionClass->getConstructor();
        //获取反射类的参数
        $parameters  = $constructor->getParameters();
        //依赖解析
        $dependencies = $this->getDependencies($parameters);

        return $reflectionClass->newInstanceArgs($dependencies);
    }

    /**
     * Notes:依赖解析
     * User: '林如信'
     * DateTime: 2023/4/15 17:50
     * @param $parameters
     * @return array
     */
    public 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[] = $this->make($parameter->getClass()->name);
            }
        }

        return $dependencies;
    }

定义好 make 方法后我们通过它来帮我们实例化 Circle 类的对象

 

        //make一个类
        $circle = $this->make(Circle::class);
        $circle->center->test();
        dd($circle->center->x);

 

 

打印正常

版权声明:
作者:linrux
链接:http://www.tot7.cn/technology/laravel/417.html
来源:阿信博客
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
< <上一篇
下一篇>>
文章目录
关闭
目 录