反射介绍
PHP 反射机制,对类、接口、函数、方法和扩展进行反向工程的能力。
分析类,接口,函数和方法的内部结构,方法和函数的参数,以及类的属性和方法。
反射中常用的几个类:
- ReflectionClass 解析类
- ReflectionProperty 类的属性的相关信息
- ReflectionMethod 类方法的有关信息
- ReflectionParameter 取回了函数或方法参数的相关信息
- ReflectionFunction 一个函数的相关信息
分析类:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31class Student
{
public $id;
public $name;
const MAX_AGE = 200;
public static $likes = [];
public function __construct($id, $name = 'li')
{
$this->id = $id;
$this->name = $name;
}
public function study()
{
echo 'learning...';
}
private function _foo()
{
echo 'foo';
}
protected function bar($to, $from = 'zh')
{
echo 'bar';
}
}
ReflectionClass
1 | $ref = new ReflectionClass('Student'); |
ReflectionProperty
1 | if ($ref->hasProperty('name')) { |
RefleactionMethod & ReflectionParameter
1 | if ($ref->hasMethod('bar')) { |
ReflectionFunction & ReflectionParameter
1 | $fun = new ReflectionFunction('demo'); |
综合实例
下面用一个简单的示例:如果用反射实例化类。
file: Student.php1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19class Student
{
public $id;
public $name;
public function __construct($id, $name)
{
$this->id = $id;
$this->name = $name;
}
public function study()
{
echo 'learning.....';
}
}
一般情况下,实例化类的时候,直接使用 new
,但是我们现在不用这种方法,我们使用反射来实现。
file: index.php1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61require 'student.php';
function make($class, $vars = [])
{
$ref = new ReflectionClass($class);
// 检查类 Student 是否可实例化
if ($ref->isInstantiable()) {
// 获取构造函数
$constructor = $ref->getConstructor();
// 没有构造函数的话,直接实例化
if (is_null($constructor)) {
return new $class;
}
// 获取构造函数参数
$params = $constructor->getParameters();
$resolveParams = [];
foreach ($params as $key => $value) {
$name = $value->getName();
if (isset($vars[$name])) {
// 判断如果是传递的参数,直接使用传递参数
$resolveParams[] = $vars[$name];
} else {
// 没有传递参数的话,检查是否有默认值,没有默认值的话,按照类名进行递归解析
$default = $value->isDefaultValueAvailable() ? $value->getDefaultValue() : null;
if (is_null($default)) {
if ($value->getClass()) {
$resolveParams[] = make($value->getClass()->name, $vars);
} else {
throw new Exception("{$name} 没有传值且没有默认值");
}
} else {
$resolveParams[] = $default;
}
}
}
// 根据参数实例化
return $ref->newInstanceArgs($resolveParams);
} else {
throw new Exception("类 {$class} 不存在!");
}
}
## 情况一
try {
$stu = make('Student', ['id' => 1]);
print_r($stu);
$stu->study();
} catch (Exception $e) {
echo $e->getMessage();
}
## 情况二
try {
$stu = make('Student', ['id' => 1, 'name' => 'li']);
print_r($stu);
$stu->study();
} catch (Exception $e) {
echo $e->getMessage();
}
上面两种情况很明显第一种,缺少参数 name
,无法实例化成功,第二种情况就可以实例化成功。
那么我们如果将类 Student
的构造函数修改为:1
2
3
4
5public function __construct($id, $name = 'zhang')
{
$this->id = $id;
$this->name = $name;
}
这样设置 name
有默认值的情况下,那么第一种情况也可以实例化成功。
情况三
第三种情况:如果在类的构造函数中有其他类为参数的情况下,那么也可以解析:1
2
3
4
5
6public function __construct($id, $name, Study $study)
{
$this->id = $id;
$this->name = $name;
$this->study = $study;
}
那么这种情况下,在分析类的构造函数参数的时候,如果没有传递参数的话,就会递归调用 make
方法处理 Study
类,如果类存在的话,实例化。
file: study.php1
2
3
4
5
6
7
8// 我们这里不写构造函数,测试下没有构造函数的情况
class Study
{
public function show()
{
echo 'show';
}
}
将 Student
类的方法 study
修改为:1
2
3
4public function study()
{
$this->name . ' ' . $this->study->show();
}
下面测试:1
2
3
4
5
6
7try {
$stu = make('Student', ['id' => 1]);
print_r($stu);
$stu->study();
} catch (Exception $e) {
echo $e->getMessage();
}
PHP 的反射是一个很用的功能,我这里只能很简单的讲解了一点皮毛,详细介绍和用法可参看 官方手册。
©版权声明:原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 & 作者信息。
End