hyperf 默认不扫描 vendor 目录,需手动在 config/autoload/scanner.php 的 paths 中添加绝对或相对路径(如 vendor/my-vendor/my-annotation-package/src),并确保注解类继承 abstractannotation、含 @annotation 标签、目标匹配且被 composer 正确加载,否则注解静默失效。

Hyperf 默认不会扫描 vendor 目录下的类,哪怕你写了自定义注解并发布为 Composer 包,只要没显式加入扫描路径,@Inject、@Aspect、@Controller 等行为就完全不会触发——不是报错,而是静默忽略。
为什么 vendor 下的注解类不被识别
Hyperf 的注解扫描器(Hyperf\Di\Scanner)只遍历 config/autoload/scanner.php 中 paths 列表指定的目录。它不会递归扫描 vendor,这是出于性能和安全考虑:第三方包数量多、结构杂,且多数无需参与 AOP 或路由注册。
常见现象包括:
- 自定义注解类(如
MyAnnotation)加了@Target({"CLASS"}),但控制器里用#[MyAnnotation]完全没反应 -
@Inject属性始终为null,且日志里出现ApplicationContext::getContainer(): Return value must be of type Psr\Container\ContainerInterface, null returned - 运行
php bin/hyperf.php route:list查不到任何注解定义的路由
必须手动把 vendor 路径加进 scanner.php
在 config/autoload/scanner.php 中扩展 paths 数组,明确告诉扫描器“这个 vendor 子目录也要扫”:
'paths' => [
'app',
'app/Provider',
'vendor/my-vendor/my-annotation-package/src', // ← 关键:指向你的注解类实际所在路径
],
注意几点:
- 路径必须是**绝对路径或相对于项目根目录的相对路径**,不能写成
vendor/autoload这种模糊形式 - 确保该路径下确实存在 PHP 类文件,且已通过 Composer 自动加载(即
composer dump-autoload已执行) - 如果注解类用了命名空间别名或 trait 引入,扫描器只认最终反射出的类定义,不解析 use 语句
- 修改后必须清空
runtime/container/proxy/和runtime/container/annotations.php,否则旧缓存会干扰新扫描结果
扫描后仍不生效?检查注解类的声明规范
即使路径加对了,注解类本身若不符合 Hyperf 注解机制,依然会被跳过。典型问题有:
- 没继承
Hyperf\Di\Annotation\AbstractAnnotation(必须) - 缺少
@AnnotationDocBlock 标签(必须) -
@Target值与实际使用位置不匹配,比如注解标注了@Target({"METHOD"})却用在类上 - 注解类文件未被 Composer 的 autoload 配置覆盖(检查
composer.json的"autoload": {"psr-4": {...}})
一个最小可运行示例:
namespace MyVendor\Annotations; <p>use Hyperf\Di\Annotation\AbstractAnnotation;</p><p>/**</p>
- @Annotation
- @Target({"CLASS"}) */ class MyController extends AbstractAnnotation { public $prefix = ''; }
依赖注入失败常伴随扫描遗漏,但根源未必在 vendor
那个 getContainer() returned null 错误,90% 是因为容器还没初始化完,你就试图在属性注入阶段访问它。而根本原因往往是:某个被 @Inject 的类,其自身或它的父类/接口,没被扫描到,导致 DI 容器无法构建完整依赖链。
所以不要只盯着 vendor;优先确认:
- 该类是否在
scanner.php的paths里 - 该类是否被正确
use且命名空间无拼写错误 - 该类构造函数参数类型是否可被容器解析(比如用了未绑定的接口)
vendor 注解的问题,本质是路径可见性问题;而注入失败,是依赖图完整性问题——两者有关联,但不能混为一谈。











