PHP 自 5.0 版本以后添加了反射机制,其中包含了一套强大的反射 API,允许在 PHP 运行环境中,访问或使用类、方法、属性、参数和注释等,其功能十分强大,经常用于高扩展的 PHP 框架、自动加载插件、自动生成文档,甚至可以用来扩展 PHP 语言。
因为反射机制是 PHP 內建的 OOP 扩展,为语言本身自带的特性,所以不需要额外添加扩展或者配置就可以使用。反射 API 会基于类、方法、属性、参数等维护相应的反射类,已提供相应的调用 API。如下表所示:
类型 | 说明 |
---|---|
Reflector | Reflector 是一个接口,被所有可导出的反射类所实现(implement) |
Reflection | 反射(reflection)类 |
ReflectionClass | 报告了一个类的有关信息 |
ReflectionZendExtension | 报告Zend扩展的相关信息 |
ReflectionExtension | 报告了PHP扩展的有关信息 |
ReflectionFunction | 报告了一个函数的有关信息 |
ReflectionFunctionAbstract | ReflectionFunction 的父类 |
ReflectionMethod | 报告了一个方法的有关信息 |
ReflectionObject | 报告了一个对象(object)的相关信息 |
ReflectionParameter | 取回了函数或方法参数的相关信息 |
ReflectionProperty | 报告了类的属性的相关信息 |
假设我们定义了一个 Websit 类,示例代码如下所示:
<?php
namespace Site;
/**
* Website 类
*/
class Website{
public $name;
private $url;
const TITLE = '城东书院';
public function __construct($name, $url){
$this->name = $name;
$this->url = $url;
}
public function getName(){
return $this->name;
}
/**
* 获取连接
* @return [type] [description]
*/
private function getUrl(){
return $this->url;
}
}
?>
想要获取 Websit 类中的属性或者方法,首先需要建立这个类的反射类实例,通过反射类的实例即可获取类中的属性或方法。不管类中定义的成员权限声明是否为 public,都可以获取到。示例代码如下所示:
<?php
$class = new \ReflectionClass('Site\\Website'); // 以类名 Website 作为参数,即可创建 Website 类的反射类
$properties = $class->getProperties(); // 以数组的形式返回 Website 类的所有属性
$property = $class->getProperty('name'); // 获取 Website 类的 name 属性
$methods = $class->getMethods(); // 以数组的形式返回 Website 类的所有方法
$method = $class->getMethod('getName'); // 获取 Website 类的 getName 方法
$constants = $class->getConstants(); // 以数组的形式获取所有常量
$constant = $class->getConstant('TITLE'); // 获取 TITLE 常量
$namespace = $class->getNamespaceName(); // 获取类的命名空间
$comment_class = $class->getDocComment(); // 获取 Website 类的注释文档,即定义在类之前的注释
$comment_method = $class->getMethod('getUrl')->getDocComment(); // 获取 Website 类中 getUrl 方法的注释文档
?>
运行上面的代码即可获取 Website 类的相应信息,这里就不再一一打印出来了,大家可以自行尝试打印。
另外,不仅可以通过反射类访问类的方法和属性,还可以创建原来类的实例或者直接调用类里面的方法。示例代码如下所示:
<?php
$class = new \ReflectionClass('Site\\Website'); // 创建 Website 类的反射类
$instance = $class->newInstance('城东书院', 'http://www.cdsy.xyz/computer/programme/PHP/'); // 创建 Website 类的实例
$instance->getName(); // 调用 Website 类的 getName 方法
$class->getProperty('name')->setValue($instance, 'C语言'); // 通过反射类设置 name 的属性值
$value = $class->getProperty('name')->getValue($instance); // 通过反射类获取 name 的属性值
$value = $class->getMethod('getUrl')->invoke($instance); // 通过反射类调用指定实例的方法,还可传入响应参数,如面下一行所示
// $value = $class->getMethod('getUrl')->invoke($instance, '城东书院'); // 通过反射类调用指定实例的方法, 并传入参数
?>
需要注意的是,在平常开发中,用到反射的地方并不多,主要是对对象进行调试,或者用来获取类的信息。在 MVC 和插件开发中,使用反射很常见,但是反射的消耗也很大,所有在可以找到替代方案的情况下,尽量不用反射。关于反射类更详细的介绍大家可以参考 https://www.php.net/manual/zh/book.reflection.php。