Container::make()先用ReflectionClass加载类,调用getConstructor()获取构造函数,再遍历getParameters()逐个解析:有类型提示则递归make(),无提示且无默认值则抛ReflectionException,接口需提前bind,标量参数不递归;构造函数声明类名需与当前类名比对确认来源。

Container::make() 调用时如何触发反射解析
调用 App::make(UserService::class) 后,容器不会直接 new,而是立刻进入反射流程:先用 ReflectionClass 加载类定义,再调用 getConstructor() 拿到构造函数反射对象。如果返回 null,说明该类没定义构造函数,跳过参数解析;否则遍历 getParameters() 逐个处理。
构造函数参数怎么被逐个解析出来
每个 ReflectionParameter 对象会调用 getType() 获取类型提示(如 CacheInterface),再用该类型名去容器里 make() ——这就触发新一轮递归解析。关键点在于:
- 若参数无类型提示(比如
$config),且没设默认值,反射会抛ReflectionException - 若类型是接口(如
UserRepositoryInterface),必须提前用App::bind()显式绑定实现类,否则make()找不到目标 - 若参数是 PHP 内置类型(如
string、int),容器不处理,留空或用默认值,不会递归
继承链中构造函数的真实来源怎么判断
ReflectionClass::getConstructor() 默认返回“实际会被调用的构造函数”,但不告诉你它属于哪一层。比如子类没写 __construct,它返回的是父类的构造函数,$constructor->class 属性显示的是父类名。要确认是否真在当前类定义,得手动比对:
- 用
$ref->getName()拿当前类名 - 用
$constructor->getDeclaringClass()->getName()拿构造函数声明所在类名 - 两者不等,说明构造函数来自父类,当前类只是继承使用
这个细节在调试“为什么注入没走子类逻辑”时特别有用——可能根本没进子类构造函数。
为什么有时候反射报 Class not found
不是类文件不存在,而是容器压根没注册过这个类名。常见原因有:
-
class_exists('app\service\UserService')返回false:Composer 自动加载失效,先跑php think optimize:autoload - 传了别名(如
'user_service')但没调过App::bind('user_service', UserService::class) - 类路径和命名空间不匹配:类
app\service\UserService必须放在app/service/UserService.php,首行namespace app\service; - 在非标准入口(比如单独写个 test.php 直接 require)启动,
bindRequest()等初始化逻辑没执行,整个容器注册树为空
反射本身不负责加载类,它只检查已加载的类结构;类加载失败,反射连入口都进不去。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











