详解PHP反射API
反射API的部分类
使用反射API这些类,可以获得在运行时访问对象、函数和脚本中的扩展的信息。通过这些信息可以用来分析类或者构建框架。
类 | 描 述 |
Reflection | 为类的摘要信息提供静态函数export() |
ReflectionClass | 类信息和工具 |
ReflectionMethod | 类方法信息和工具 |
ReflectionParameter | 方法参数信息 |
ReflectionProperty | 类属性信息 |
ReflectionFunction | 函数信息和工具 |
ReflectionExtension | PHP扩展信息 |
ReflectionException | 错误类 |
获取类的信息
我们在工作中使用过一些用于检查类属性的函数,例如:get_class_methods、getProduct等。这些方法对获取详细类信息有很大的局限性。
我们可以通过反射API类:Reflection 和 ReflectionClass 提供的静态方法 export 来获取类的相关信息, export 可以提供类的几乎所有的信息,包括属性和方法的访问控制状态、每个方法需要的参数以及每个方法在脚本文档中的位置。这两个工具类, export 静态方法输出结果是一致的,只是使用方式不同。
首先,构建一个简单的类
<?php
class Student {
public $name;
protected $age;
private $sex;
public function __construct($name, $age, $sex)
{
$this->setName($name);
$this->setAge($age);
$this->setSex($sex);
}
public function setName($name)
{
$this->name = $name;
}
protected function setAge($age)
{
$this->age = $age;
}
private function setSex($sex)
{
$this->sex = $sex;
}
}
使用 ReflectionClass::export() 获取类信息
ReflectionClass::export('Student');
打印结果:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
ReflectionClass类提供了非常多的工具方法,官方手册给的列表如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
使用 Reflection::export() 获取类信息
$prodClass = new ReflectionClass('Student');
Reflection::export($prodClass);
打印结果
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
创建 ReflectionClass对象后,就可以使用 Reflection 工具类输出 Student 类的相关信息。Reflection::export() 可以格式化和输出任何实现 Reflector 接口的类的实例。
检查类
前面我们了解的 ReflectionClass 工具类,知道此类提供了很多的工具方法用于获取类的信息。例如,我们可以获取到 Student 类的类型,是否可以实例化
工具函数
function classData(ReflectionClass $class) {
$details = '';
$name = $class->getName(); // 返回要检查的类名
if ($class->isUserDefined()) { // 检查类是否由用户定义
$details .= "$name is user defined" . PHP_EOL;
}
if ($class->isInternal()) { // 检查类是否由扩展或核心在内部定义
$details .= "$name is built-in" . PHP_EOL;
}
if ($class->isInterface()) { // 检查类是否是一个接口
$details .= "$name is interface" . PHP_EOL;
}
if ($class->isAbstract()) { // 检查类是否是抽象类
$details .= "$name is an abstract class" . PHP_EOL;
}
if ($class->isFinal()) { // 检查类是否声明为 final
$details .= "$name is a final class" . PHP_EOL;
}
if ($class->isInstantiable()) { // 检查类是否可实例化
$details .= "$name can be instantiated" . PHP_EOL;
} else {
$details .= "$name can not be instantiated" . PHP_EOL;
}
return $details;
}
$prodClass = new ReflectionClass('Student');
print classData($prodClass);
打印结果
Student is user defined
Student can be instantiated
除了获取类的相关信息,还可以获取 ReflectionClass 对象提供自定义类所在的文件名及文件中类的起始和终止行等相关源代码信息。
function getClassSource(ReflectionClass $class) {
$path = $class->getFileName(); // 获取类文件的绝对路径
$lines = @file($path); // 获得由文件中所有行组成的数组
$from = $class->getStartLine(); // 提供类的起始行
$to = $class->getEndLine(); // 提供类的终止行
$len = $to - $from + 1;
return implode(array_slice($lines, $from - 1, $len));
}
$prodClass = new ReflectionClass('Student');
var_dump(getClassSource($prodClass));
打印结果
string 'class Student {
public $name;
protected $age;
private $sex;
public function __construct($name, $age, $sex)
{
$this->setName($name);
$this->setAge($age);
$this->setSex($sex);
}
public function setName($name)
{
$this->name = $name;
}
protected function setAge($age)
{
$this->age = $age;
}
private function setSex($sex)
{
$this->sex = $sex;
}
}
' (length=486)
我们看到 getClassSource 接受一个 ReflectionClass 对象作为它的参数,并返回相应类的源代码。该函数忽略了错误处理,在实际中应该要检查参数和结果代码!