若转载教程,请注明出自SW-X框架官方文档
1、类的反射机制
反射是什么?
它是指在PHP运行状态中,扩展分析PHP程序,导出或提取出关于类、方法、属性、参数等的详细信息,包括注释。
这种动态获取的信息以及动态调用对象的方法的功能称为反射API。
反射是操纵面向对象范型中元模型的API,其功能十分强大,可帮助我们构建复杂,可扩展的应用。
其用途如:自动加载插件,自动生成文档,甚至可用来扩充PHP语言。
PHP反射api由若干类组成,可帮助我们用来访问程序的元数据或者同相关的注释交互。
借助反射我们可以获取诸如类实现了那些方法,创建一个类的实例(不同于用new创建),调用一个方法(也不同于常规调用),传递参数,动态调用类的静态方法。
反射api是PHP内建的面向对象技术的扩展,包括一些类,异常和接口,综合使用他们可用来帮助我们分析其它类,接口,方法,属性,方法和扩展。
这些面向对象的扩展被称之为反射。
在Class反射机制中,用得比较多的是ReflectionClass类 和 ReflectionMethod类。
所有Reflectio类可以参考官方手册:http://php.net/manual/zh/book.reflection.php。
A、ReflectionClass类的主要作用
ReflectionClass类是PHP系统自带提供的一个Class,该类主要用于打印出指定类的内部结构,类似于var_dump()函数的功能,但使用ReflectionClass类,反射出的对象结构,要比var_dump()函数打印出来的内容要丰富很多。
通过ReflectionClass类,我们可以获得对象结构的以下信息:
1、获得类的成员属性列表
2、获得类的成员函数列表
3、检测类是否为final或者abstract
4、检测类是否含有某个成员函数
B、通过ReflectionClass类实例化自定义类
ReflectionClass类的返回值比较特殊,在该类实例化时,需要参入一个自定义类的名称,用于获得该类的内部结构,
同时,如果我们需要实例化自定义类的话,可以使用ReflectionClass的newInstanceArgs()成员函数,
该方法的传参是一个数组,并将其转换为变量,传入自定义类的构造函数中。
详细使用案例如下:
<?php
# 自定义类
class Test {
public function __construct($name){
echo $name;
}
}
# 使用ReflectionClass类
$class = new ReflectionClass('Test');
# 使用newInstanceArgs()成员函数实例化自定义类
$class->newInstanceArgs(['name'=>'你妹']);
C、通过ReflectionClass类获得成员属性名称
如果我们需要获得自定义类的内部的成员属性名称时,可以使用ReflectionClass的getProperties()成员函数,
该函数的返回值是一个数组:
<?php
# 自定义类
class Test {
public $name;
private $id;
protected $appid;
}
# 使用ReflectionClass类
$class = new ReflectionClass('Test');
# 使用getProperties()成员函数,获得自定义类的成员属性名称
$properties = $class->getProperties();
foreach ($properties as $property) {
echo $property->getName().'<br/>';
}
通过运行上面的代码,细心的朋友可能已经发现了,
上面分别有public、private、protected三种控制权限的成员属性,
但getProperties()成员函数都直接将其获得了,但并没有返回这些成员属性所对应的控制权限分别是什么?
如果只想获取得指定权限的成员属性,getProperties()成员函数就要额外传递一个参数:
$res = $class->getProperties(参数);
可用的参数列表如下:
1、ReflectionProperty::IS_STATIC,获得静态成员属性名称
2、ReflectionProperty::IS_PUBLIC,获得public权限成员属性名称
3、ReflectionProperty::IS_PROTECTED,获得protected权限成员属性名称
4、ReflectionProperty::IS_PRIVATE,获得private权限成员属性名称
范围查询使用 | 符号进行分割(相当于OR)
多条件重新使用 && 符号进行分割(相当于AND)
具体使用代码如下:
<?php
# 自定义类
class Test {
public $name;
private $id;
protected $appid;
}
# 使用ReflectionClass类
$class = new ReflectionClass('Test');
# 获得public权限的成员属性名称
$properties = $class->getProperties(ReflectionProperty::IS_PUBLIC);
foreach ($properties as $property) {
echo 'public:'.$property->getName().'<br/>';
}
D、通过ReflectionClass类获得成员属性对应的注释
ReflectionClass类获得成员属性对应的注释内容是有许多限制的,其中有一条特别重要,只能使用:
/**
* 注释内容
*/
这样的注释风格,同时注释必须紧贴上成员属性上一行中。
在对使用getProperties()成员函数获得成员属性名次后,再对应使用->getDocComment()成员函数,
就能获得其对应的注释内容,案例代码如下:
<?php
# 自定义类
class Test {
/**
* 草拟妹
*/
public $name;
private $id;
protected $appid;
}
# 使用ReflectionClass类
$class = new ReflectionClass('Test');
# 获得public权限的成员属性名称
$properties = $class->getProperties(ReflectionProperty::IS_PUBLIC);
foreach ($properties as $property) {
# 获得成员属性对应的注释内容
# 注意:这里是对$property变量使用getDocComment()成员函数
$docblock = $property->getDocComment();
var_dump($docblock);
}
E、通过ReflectionClass类获得成员函数名称
如果我们需要获得自定义类的内部的成员函数名称时,可以使用ReflectionClass的getMethods()成员函数,
该函数的返回值是一个数组:
<?php
# 自定义类
class Test {
public function A() {}
private function B() {}
protected function C() {}
}
# 使用ReflectionClass类
$class = new ReflectionClass('Test');
# 获得成员函数
$methods = $class->getMethods();
foreach ($methods as $method) {
echo '方法名称:'.$method->name.'<br/>';
}
通过运行上面的代码,细心的朋友可能已经发现了,
上面分别有public、private、protected三种控制权限的成员函数,
但getMethods()成员函数都直接将其获得了,但并没有返回这些成员函数所对应的控制权限分别是什么?
如果只想获取得指定权限的成员函数,那么getMethods()成员函数就要额外传递一个参数:
$res = $class->getMethods(参数);
可用的参数列表如下:
1、ReflectionMethod::IS_STATIC,获得静态成员函数名称
2、ReflectionMethod::IS_PUBLIC,获得public权限成员函数名称
3、ReflectionMethod::IS_PROTECTED,获得protected权限成员函数名称
4、ReflectionMethod::IS_PRIVATE,获得private权限成员函数名称
5、ReflectionMethod::IS_ABSTRACT,获得抽象的成员函数名称
6、ReflectionMethod::IS_FINAL,获得唯一的成员函数名称
范围查询使用 | 符号进行分割(相当于OR)
多条件重新使用 && 符号进行分割(相当于AND)
具体使用代码如下:
<?php
# 自定义类
class Test {
public function A() {}
private function B() {}
protected function C() {}
}
# 使用ReflectionClass类
$class = new ReflectionClass('Test');
# 获得成员函数
$methods = $class->getMethods();
foreach ($methods as $method) {
echo '类名:'.$method->class.' ';
echo '方法名称:'.$method->name.'<br/>';
}
F、通过ReflectionClass类获得成员函数对应的注释
ReflectionClass类获得成员函数对应的注释内容是有许多限制的,其中有一条特别重要,只能使用:
/**
* 注释内容
*/
这样的注释风格,同时注释必须紧贴上成员函数上一行中。
在对使用getDocComment()成员函数获得成员函数名之后,再对应使用->getDocComment()成员函数,与成员属性用法一致,
就能获得其对应的注释内容,案例代码如下:
<?php
# 自定义类
class Test {
/**
* 尼妹的函数
* @param string $name 打死你
* @return void
*/
public function A() {}
}
# 使用ReflectionClass类
$class = new ReflectionClass('Test');
# 获得成员函数名称
$methods = $class->getMethods();
foreach ($methods as $method) {
# 获得成员函数对应的注释内容
var_dump($method->getDocComment());
}
G、成员属性 和 成员函数的注释风格
鉴于反射机制只能获得到
/**
* 注释内容
*/
这样的注释方式,所以不管是成员函数还是成员属性,都应该统一使用这种注释风格。
详细参考如下:
<?php
class Test {
/**
* 名称
*/
public $name;
/**
* 年龄
*/
private $age;
/**
* 尼妹的函数
* @param string $name 打死你
* @return void
*/
public function A() {}
}
H、成员属性、成员函数和Class类的命名规范
不管是成员属性还是成员函数:
public、protected类型的,使用小驼峰命名法,例如:$orderType;
private类型的,使用下划线_开头,加小驼峰命名法,例如:$_orderType;
什么是驼峰命名?
就是当变量名或函数名是由一个或多个单词连结在一起,而构成的唯一识别字时,第一个单词以小写字母开始;
第二个单词的首字母大写或每一个单词的首字母都采用大写字母,例如:$myFirstName、$myLastName,这样的变量名看上去就像骆驼峰一样此起彼伏,故得名。
小驼峰法:除第一个单词之外,其他单词首字母大写。
大驼峰法:相比小驼峰法,大驼峰法把第一个单词的首字母也大写了
而Class类一般都是使用大驼峰命名法。
详细参考如下:
<?php
class TestApi {
/**
* 订单类型
*/
public $orderType;
/**
* 订单ID号
*/
private $_orderId;
/**
* 尼妹的函数
* @param string $name 打死你
* @return void
*/
public function orderBack() {}
}
I、成员函数注释中的标记元说明
在成员函数的注释中,我们通常会看见两个标记元,就是:@param和@return。
而除了这2个标记元外,PHP中通常还存在以下这些标记元信息, 他们通常代表着IT界的注释规范:
标记元 | 描述 |
---|---|
@access | 该标记元用于指明的权限:private、public或proteced |
@author | 指明作者 |
@copyright | 指明版权信息 |
@version | 指明版本信息 |
@deprecated | 指明不用或者废弃的关键字,例如说明这个方法在哪个版本之后即将弃用 |
@global | 指明在此成员函数中引用了哪些全局变量 |
@license | 相当于html标签中的,首先是URL,接着是要显示的内容 例如百度 可以写作 @license http://www.baidu.com 百度 |
@final | 指明是一个唯一的类、方法、属性,禁止派生、修改。 |
@abstrcut | 说明当前类是一个抽象类或抽象函数 |
@static | 说明当前方法、属性是静态的。 |
@todo | 指明应该改进或没有实现的地方 |
@throws | 指明此成员函数可能抛出的错误异常,以及其发生的情况 |
@param | 指明一个函数的参数,包含类型、参数名称、参数描述等 |
@return | 指明一个函数的返回值,包含类型 |
详细的注释风格可以参照下列案例,在实际项目中,并不是所有标记元都会全部用上,需要看团队具体的使用要求,下面代码仅供参考:
<?php
class TestApi {
/**
* 尼妹的
* 这是一个给小黄牛用的函数,哈哈,不服你来打我啊
*
* @author 小黄牛
* @version v1.0.0.1
* @deprecated v1.0.9.* 版本后弃用
* @global 无
* @todo 后期这个函数需要优化到神一样的执行速度
* @param string $name 打死你
* @return void
*/
public function orderBack() {}
}
不过朋友们需要注意的是,每个标记元之间,都是使用一个空格进行分割,标记元例如@param中的参数间隔也是如此,
千万不要跟面向过程中的function(){}自定义封装函数的规范搞混了。
不过function(){}自定义封装函数注释中的标记元,可以参考上面的。
注意:ReflectionMethod 类是一个基于ReflectionClass 类的反射机制的扩展类,两个类混合使用可以实现许多功能,朋友们可以参照课件中的官方手册,尝试使用下ReflectionMethod 类。