@inject 注解仅在控制器由 hyperf 容器创建时生效;手动 new 实例会失效,需确保类有 @controller/@autocontroller 注解且依赖已注册,接口注入须配 name 绑定。

Inject 注解在控制器里能用,但必须满足容器管理前提——控制器本身得由 Hyperf 容器实例化,不能 new 出来;否则注入字段会是 null 或抛异常。
控制器必须由容器创建,否则 @Inject 不生效
Hyperf 的 @Inject 本质依赖 AOP 代理机制:只有被容器创建、且类上存在 @Inject 注解时,才会生成代理类并在构造后自动填充属性。手动 new IndexController() 绕过了容器,代理不触发,@Inject 彻底失效。
- ✅ 正确方式:控制器通过路由访问(如
GET /index),由框架内部调用$container->get(IndexController::class) - ❌ 错误方式:在其他地方写
$ctrl = new IndexController(),此时@Inject字段保持未初始化状态 - ⚠️ 验证方法:在控制器方法里
var_dump($this->userService),非 null 才说明注入成功
@Inject 注入 UserService 等具体类的写法
注入已注册到 DI 容器的类(如 UserService)最直接,不需要额外配置,前提是该类已被扫描并绑定(默认开启)。
- 在控制器顶部
use相关注解和类:use Hyperf\Di\Annotation\Inject;、use App\Service\UserService; - 声明属性并加注解:
#[Inject]+/** @var UserService */+private UserService $userService; - 注意 PHP 8.0+ 推荐使用属性注解
#[Inject],老版本用 PHPDoc 风格/** @Inject */ - 不要在构造函数里重复赋值,
@Inject是属性级注入,不是构造注入
注入接口(多实现)时必须指定 name
当一个接口(如 UserServiceInterface)有多个实现类(AliyunUserService、QcloudUserService),直接 @Inject 会报 ContainerException: Cannot resolve type "App\Contract\UserServiceInterface"。
- 必须在
config/autoload/dependencies.php中注册命名绑定,例如:'App\Contract\UserServiceInterface@aliyun' => App\Service\AliyunUserService::class - 控制器中显式指定:
#[Inject(name: 'aliyun')],name 值要和@xxx后缀完全一致(区分大小写) - 漏掉
name参数、拼写错误、或没注册对应@xxx映射,都会导致注入失败 - 运行时动态获取可改用
$this->container->make(UserServiceInterface::class, ['name' => 'aliyun'])
required=false 可避免启动时报错,但要小心 null 引用
@Inject 默认 required=true,如果依赖类未注册或路径错误,服务启动直接失败;设为 false 可跳过,但后续调用可能出 Call to a member function on null。
- 写法示例:
#[Inject(required: false)] private ?UserServiceInterface $optionalService; - 必须配合类型提示中的
?(PHP 8.0+)或private $optionalService;+ 运行时判空 - 仅建议用于真正可选的辅助服务(如日志上报开关),核心业务依赖不建议设为 false
- 设了
required=false后,务必检查所有调用点是否做了if ($this->optionalService) { ... }
最容易被忽略的是:控制器类没被注解标记(比如漏了 #[Controller] 或 #[AutoController]),会导致整个类不被容器管理,@Inject 形同虚设——连代理类都不会生成。











