本文目录导读:

PHP反射机制(Reflection)是PHP提供的一套API,允许程序在运行时检查、分析和操作类、方法、属性、参数等结构信息,它就像一面“镜子”,让程序能够看见自己。
核心概念
什么是反射?
- 运行时:不需要在代码编译阶段就确定结构
- 自省:程序可以检查自身
- 动态操作:可以调用方法、修改属性,即使这些在编写时并不知道
主要反射类
ReflectionClass // 分析类 ReflectionMethod // 分析方法 ReflectionProperty // 分析属性 ReflectionParameter // 分析参数 ReflectionFunction // 分析函数 ReflectionObject // 分析对象
简单示例
class User {
private $name;
protected $email;
public function __construct($name, $email) {
$this->name = $name;
$this->email = $email;
}
public function getName() {
return $this->name;
}
private function secret() {
return "这是私有方法";
}
}
// 基本反射使用
$reflection = new ReflectionClass('User');
// 检查类的属性
$properties = $reflection->getProperties();
foreach ($properties as $property) {
echo $property->getName() . ' - ' . $property->getVisibility() . "\n";
}
// 调用私有方法
$method = $reflection->getMethod('secret');
$method->setAccessible(true); // PHP 8.1+ 不再需要
$user = new User('John', 'john@example.com');
echo $method->invoke($user); // 输出: 这是私有方法
实际应用场景
依赖注入容器
class Container {
private $services = [];
public function resolve($class) {
$reflection = new ReflectionClass($class);
// 获取构造函数
$constructor = $reflection->getConstructor();
if (!$constructor) {
return new $class(); // 无构造函数
}
// 解析构造函数的依赖
$params = $constructor->getParameters();
$dependencies = [];
foreach ($params as $param) {
$type = $param->getType();
if ($type && !$type->isBuiltin()) {
// 递归创建依赖
$dependencies[] = $this->resolve($type->getName());
}
}
return $reflection->newInstanceArgs($dependencies);
}
}
ORM(对象关系映射)
class ORM {
public function save($object) {
$reflection = new ReflectionObject($object);
// 自动获取所有属性
$properties = $reflection->getProperties();
$data = [];
foreach ($properties as $property) {
$property->setAccessible(true);
$data[$property->getName()] = $property->getValue($object);
}
// 根据表名生成 SQL
$table = strtolower($reflection->getShortName());
// 动态构建 INSERT 语句...
}
public function hydrate($class, $row) {
$object = new $class();
$reflection = new ReflectionObject($object);
// 将数组数据填充到对象属性
foreach ($row as $column => $value) {
if ($reflection->hasProperty($column)) {
$property = $reflection->getProperty($column);
$property->setAccessible(true);
$property->setValue($object, $value);
}
}
return $object;
}
}
自动文档生成
function generateDoc($class) {
$reflection = new ReflectionClass($class);
$doc = "# {$reflection->getShortName()}\n\n";
// 生成方法文档
foreach ($reflection->getMethods() as $method) {
if ($method->isPublic()) {
$doc .= "## {$method->getName()}\n";
// 获取方法参数
foreach ($method->getParameters() as $param) {
$doc .= "- {$param->getName()}: ";
if ($param->hasType()) {
$doc .= $param->getType();
}
$doc .= "\n";
}
}
}
return $doc;
}
调试和测试工具
class Debugger {
public static function inspect($object) {
$reflection = new ReflectionObject($object);
echo "类名: " . $reflection->getName() . "\n";
echo "父类: " . ($reflection->getParentClass() ? $reflection->getParentClass()->getName() : '无') . "\n";
echo "实现的接口: " . implode(', ', $reflection->getInterfaceNames()) . "\n";
// 调试方法执行时间
foreach ($reflection->getMethods() as $method) {
if ($method->isPublic()) {
$start = microtime(true);
// 可以调用方法...
$end = microtime(true);
echo "{$method->getName()}: " . ($end - $start) . "秒\n";
}
}
}
}
高级特性
动态代理模式
class ProxyFactory {
public static function create($targetClass) {
return new class($targetClass) {
private $target;
public function __construct($target) {
$this->target = new $target();
}
public function __call($name, $arguments) {
// 在调用前做日志记录
echo "调用: $name\n";
$reflection = new ReflectionClass($this->target);
if ($reflection->hasMethod($name)) {
$method = $reflection->getMethod($name);
return $method->invokeArgs($this->target, $arguments);
}
}
};
}
}
注解处理(PHP 8+)
#[Table('users')]
class User {
#[Column('username')]
public $name;
#[Validate(['required', 'email'])]
public function setEmail($email) {
$this->email = $email;
}
}
$reflection = new ReflectionClass(User::class);
$attributes = $reflection->getAttributes();
foreach ($attributes as $attribute) {
echo $attribute->getName(); // Table
echo $attribute->getArguments()[0]; // users
}
性能注意事项
// 缓存反射结果(推荐)
class ReflectionCache {
private static $cache = [];
public static function get($class) {
if (!isset(self::$cache[$class])) {
self::$cache[$class] = new ReflectionClass($class);
}
return self::$cache[$class];
}
}
反射的优势:
- 灵活性高,支持动态操作
- 框架开发的基础(Laravel、Symfony等)
- 实现魔术方法无法实现的功能
- 代码生成和自动化处理
使用注意:
- 性能比直接调用慢(可缓存优化)
- 代码可读性降低
- 过度使用会使代码难以维护
- PHP 8.1+ 对私有属性访问限制更加严格
理解反射的关键是:它不是日常业务代码的常用工具,而是高级框架和工具的核心基础设施,当你需要处理未知结构或实现自动化时,反射就派上用场了。