make() 不触发属性注入,因其仅执行构造函数参数解析,跳过aop阶段的registerinjectpropertyhandler;属性注入需类被容器get()或经@controller/@service扫描注册后才生效。

make 创建的对象属性为何不被注入
因为 make() 默认只做构造函数参数注入,不触发属性级注解(如 #[Inject])的处理。Hyperf 的属性注入是 AOP 阶段由 RegisterInjectPropertyHandler 完成的,而该逻辑仅在容器通过 get() 或自动路由实例化(如 Controller)时才执行。
-
make()本质是“浅层实例化”:它调用ObjectResolver解析构造函数,但跳过 AOP 属性处理器链 - 即使类里写了
#[Inject] private UserService $userService;,make(UserService::class)也不会设置这个属性 - 只有通过
$container->get(UserService::class)或被@Controller/@Service标记且被扫描注册的类,在首次get()时才会走完整注入流程
如何确认类是否被正确扫描并启用 Inject 注解
不能只看代码里有没有写 #[Inject],关键要看这个类是否进入了 DI 容器的“可注入对象清单”。Hyperf 不会为任意类启用注解处理,必须满足两个硬性条件:
- 类文件位于
config/autoload/annotations.php的scan.scan_dirs列表中(例如app/) - 类本身或其父类/接口上有“激活型注解”,如
@Controller、@Service、@Aspect;仅#[Inject]在属性上不构成扫描入口 - 检查
php bin/hyperf.php di:dump输出中是否存在该类全名——没出现就说明没被扫描,注解再全也无效
Inject 属性注入失败的典型报错与定位
最常见的错误不是“找不到类”,而是容器在尝试反射设置属性时拿不到容器实例,抛出:Hyperf\Context\ApplicationContext::getContainer(): Return value must be of type Psr\Container\ContainerInterface, null returned。这说明属性注入流程已启动,但上下文丢失。
- 该错误多发生在非容器生命周期内手动 new 对象后又试图触发注入(比如在普通工具类里调用
new SomeService()再期望#[Inject]生效) - 也出现在
make()后对返回对象二次调用$container->get()但上下文未切换的场景 - 验证方式:在类构造函数里加
var_dump(ApplicationContext::getContainer() !== null);,若为false,说明当前不在容器管理生命周期内
替代方案:让 make 出的对象也能注入属性
没有直接开关让 make() 支持属性注入,但可通过组合调用绕过限制:
- 改用
$container->get(SomeService::class)替代make(),前提是该类已注册为单例或能被自动解析 - 若必须短生命周期,可在类内部延迟获取依赖:
private ?UserService $userService = null; public function getUserService(): UserService { return $this->userService ??= ApplicationContext::getContainer()->get(UserService::class); } - 对
make()结果手动补注入(不推荐):$obj = make(SomeService::class); $container->invoke($obj);—— 但invoke()只处理方法注入,不处理属性
真正容易被忽略的是:Hyperf 的属性注入和构造函数注入走的是两条不同路径,前者强依赖容器上下文与 AOP 注册,后者只靠反射和定义表。混用 make() 和 #[Inject] 属性,本质上是在用构造函数注入的壳,装属性注入的逻辑,必然断裂。











