反射类怎么用?

很久之前用过关于反射相关的函数,一直没时间整理,趁下班等巴士的这段时间,整理下


1.反射是什么?

它是指在PHP运行状态中,扩展分析PHP程序,导出或提取出关于类、方法、属性、参数等的详细信息,包括注释。这种动态获取的信息以及动态调用对象的方法的功能称为反射API。
反射是操纵面向对象范型中元模型的API,其功能十分强大,可帮助我们构建复杂,可扩展的应用。

2. 反射应用场景

  • 生成文档(生成代码文档,方便查阅)
  • 自动加载插件(使用加载的配置类,比如系统的配置文件,过滤常量)
  • 加载第三方封装类库(加载类库,调用相关方法)

3. 实例代码

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
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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
//校验配置,注入配置,统一执行
<?php
abstract class Module
{
#核心Module类库
function baseFunc()
{
echo "I am baseFunc";
}
abstract function execute();
}

class ModuleRunner
{
#模拟配置,动态配置需要加载的Module
public static $config = array (
"CmiModule" => array("cmi" => "GLOBAL"),
"FtpModule" => array("host" => "dengke.com", "user" => "wdk")
);

private $modules = array();

#初始化ModuleRunner,加载配置中的Module
function init()
{
$parent = new ReflectionClass("Module");
foreach(self::$config as $cName => $params)
{
#检查配置中的Module是否合法
$mClass = new ReflectionClass($cName);
#检查是否是Module的子类型
if(! $mClass->isSubclassOf($parent)) {
throw new Exception("unknown type : {$cName}");
}

$module = $mClass->newInstance();
#检查配置中的函数的参数格式是否正确
foreach($mClass->getMethods() as $method)
{
$this->handleMothod($module, $method, $params);
}
#加载Module
array_push($this->modules, $module);
/*foreach ($this->modules as $key => $value) {
$value->execute();
}*/
}
}

#检查Module中的方法参数是否和传入的$params名字相同,并且具有set方法
private function handleMothod(Module $module, ReflectionMethod $method, $params)
{
$name = $method->getName();
$args = $method->getParameters();

#如果没有配置中的类的方法的参数个数不为1,或者方法名前3个字母不为set,返回false
if(count($args) != 1 || substr($name, 0, 3) != "set") {
return false;
}

#如果方法名后三个字母与配置中的参数名不同,返回false
$property = strtolower(substr($name, 3));
if(!isset($params[$property])) {
return false;
}
#获取参数的类型
$argClass = $args[0]->getClass();
if (empty($argClass)) {
//如果得到的类为空证明需要传递基础类型参数
$method->invoke($module, $params[$property]);
} else {
//如果不为空说明需要传递真实对象
$method->invoke($module, $argClass->newInstance($params[$property]));
}
}

public function getModules()
{
return $this->modules;
}
}

class FtpModule extends Module
{
#用户自定义第三方Module
private $host = "default host";
private $user = "default user";

function setHost($host)
{
$this->host = $host;
//echo $this->host;=>dengke.com
}

function setUser($user)
{
$this->user = $user;
//echo $this->user;=>wdk
}

function execute()
{
echo "{$this->user} user {$this->host}";
}
}

class CMI
{
#第三方类
public $name;
function __construct($name)
{
$this->name = $name;
}
}

class CmiModule extends Module
{
#用户自定义第三方Module
private $CMI;
function setCMI(CMI $CMI)
{
$this->CMI = $CMI;
}

function execute()
{
if (is_object($this->CMI)) {
echo "i an this->cmi";
} else {
echo "ERROR";
}
}
}

$modRunner = new ModuleRunner();
$modRunner->init();
//var_dump($modRunner);

到此程序结束,init启动会自动调用构造方法,初始化要加载类库的其他成员属性,包括初始化和执行相应方法操作,这里只是完成了对应的set方法。其中$this->modules属性保存了所有调用类的对象,每个对象包含数据,可以遍历包含的对象来以此调用execute()方法。

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
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
<?php
//针对不同API定义不同API参数CONSTANT,通过反射来校验参数正确性
class loanField {
static $fpFilterField = array (
'order_code',
);
static $fpLoanRequiredField = array(
'unit',
'duration',
'profile',
'rate',
'total_rate',
'merchant_uid',
'credit_type',
'credit_name',
'finance_amount',
'service_amount',
'actual_amount',
'repayment_style',
'credit_supplier',
);

static function fpRquiredField()
{
return array_merge(self::$fpFilterField, self::$fpLoanRequiredField);
}

//调用实例
public function getFieldList($class, $method)
{
if (!$this->fieldList) {
$this->fieldList = $this->createFieldList($class, $method);
}
return $this->fieldList;
}

protected function createFieldList($class, $method)
{
$reflectObj = new ReflectionClass($class);
if ($reflectObj->hasMethod($method)) {
$method = $reflectObj->getmethod($method);
return (array) $method->invoke($reflectObj->newInstance());
} else if ($reflectObj->hasConstant($method)) {
return $reflectObj->getconstant($method);
} else {
return (array) $reflectObj->getStaticPropertyValue($method);
}
}

public function verifyLoanField()
{
$requireField = $this->getFieldList('loanField', 'fpRquiredField');
$loanInfo = (array) $this->request;
if (!$this->verifyIsExist($requireField, $loanInfo)) {
return false;
}
return true;
}
}

不同的API封装不同的过滤参数,通过反射调用来校验正确性

…………..未完,待整理

-------------本文结束感谢您的阅读-------------
坚持原创技术分享,您的支持将鼓励我继续创作!