一、前言
在现代 PHP 框架(如 Laravel、Symfony、ThinkPHP 8)中,依赖注入(Dependency Injection, DI) 和 控制反转(Inversion of Control, IoC) 是核心设计理念。
它们让我们可以更优雅地管理对象依赖,而不是手动 new 一堆对象。
那么框架底层是如何知道一个类需要哪些依赖?
答案就是 —— Reflection(反射)。
PHP 提供了一套功能强大的反射 API,而 ReflectionClass 是其中的核心。
本文将带你从基础到实践,掌握它的用法,并手写一个迷你的依赖注入容器。
二、什么是 ReflectionClass?
ReflectionClass 是 PHP 提供的一个内置类,用于在运行时动态地分析、操作类的结构。
你可以通过反射:
- 查看类名、属性、方法;
- 获取构造函数;
- 实例化类;
- 访问私有属性;
- 读取注释(DocBlock);
- 实现自动依赖注入。
<?php
class User {
public $name;
private $age;
public function __construct($name, $age) {
$this->name = $name;
$this->age = $age;
}
public function sayHello() {
return "Hello, " . $this->name;
}
}
$ref = new ReflectionClass('User');
$instance = $ref->newInstanceArgs(['木子', 25]);
echo $instance->sayHello(); // Hello, 木子
✅ 通过反射,我们在不知道构造函数签名的情况下,也能动态创建对象。
三、ReflectionClass 常用方法
| 方法 | 功能 |
|---|---|
getName() |
获取类名 |
getConstructor() |
获取构造函数 |
getMethods() |
获取所有方法 |
getProperties() |
获取所有属性 |
getConstants() |
获取常量 |
newInstanceArgs() |
传入参数创建对象 |
getDocComment() |
获取类的注释 |
getParentClass() |
获取父类信息 |
getInterfaceNames() |
获取实现的接口 |
四、反射的实际用途
- 框架自动依赖注入(DI Container)
- 控制器路由自动绑定
- ORM 模型自动映射数据库字段
- 动态 Mock 测试
- 解析注释(DocBlock)或 PHP 8 Attributes
换句话说:Reflection 是很多框架“魔法”的基础。
五、手写一个迷你依赖注入容器
(1)定义几个有依赖的类
<?php
class Logger {
public function log($msg) {
echo "[LOG] $msg\n";
}
}
class UserRepository {
protected $logger;
public function __construct(Logger $logger) {
$this->logger = $logger;
}
public function save($user) {
$this->logger->log("保存用户:{$user}");
}
}
class UserService {
protected $repo;
public function __construct(UserRepository $repo) {
$this->repo = $repo;
}
public function register($name) {
$this->repo->save($name);
}
}
依赖关系:
UserService → UserRepository → Logger
(2)实现容器类
<?php
class Container
{
protected $instances = [];
public function bind($abstract, $concrete = null)
{
$this->instances[$abstract] = $concrete ?? $abstract;
}
public function make($class)
{
$ref = new ReflectionClass($class);
// 没有构造函数,直接实例化
$constructor = $ref->getConstructor();
if (!$constructor) {
return new $class;
}
$params = $constructor->getParameters();
$dependencies = [];
foreach ($params as $param) {
$type = $param->getType();
if ($type && !$type->isBuiltin()) {
$depClass = $type->getName();
$dependencies[] = $this->make($depClass);
} else {
if ($param->isDefaultValueAvailable()) {
$dependencies[] = $param->getDefaultValue();
} else {
throw new Exception("无法解析参数:{$param->getName()}");
}
}
}
return $ref->newInstanceArgs($dependencies);
}
}
(3)使用容器自动注入依赖
<?php
$container = new Container();
$userService = $container->make(UserService::class);
$userService->register('木子');
输出结果:
[LOG] 保存用户:木子
六、实现原理解析
ReflectionClass获取类的构造函数;- 调用
getParameters()获取构造参数; - 判断每个参数是否是一个类(类型提示);
- 如果是类类型,则递归调用
make(); - 最终用
newInstanceArgs()创建完整对象树。
这样就实现了自动依赖注入,而不需要手动 new 多层依赖。
七、扩展:单例绑定与接口映射
让某些类只实例化一次:
public function singleton($abstract, $concrete = null)
{
$this->instances[$abstract] = $this->make($concrete ?? $abstract);
}
或者绑定接口:
$container->bind(LoggerInterface::class, FileLogger::class);
这样框架就能自动解析接口对应的实现类。
八、总结
- ✅
ReflectionClass的核心用法 - ✅ 如何用反射分析构造函数参数
- ✅ 如何实现一个简易的依赖注入容器
- ✅ 容器在框架中的应用场景
ReflectionClass 是理解现代 PHP 框架底层机制的关键。
当你掌握它,很多“框架魔法”都会变得清晰、可控。
💡延伸阅读
- PHP 官方文档:ReflectionClass
- Laravel 源码分析:
Illuminate\Container\Container - 设计模式相关:依赖注入、控制反转、服务容器
正文完