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
链接:https://www.tot7.cn/technology/laravel/417.html
来源:阿信博客
文章版权归作者所有,未经允许请勿转载。
共有 0 条评论