AnnotationCollector::getAnnotationsByClass() 返回键为注解类完整命名空间、值为注解实例的数组,不包含类名或方法名信息;目标上下文需通过注解处理器参数 $className 和 $methodName 获取。

AnnotationCollector::getAnnotationsByClass() 返回的是什么
它返回一个 array,键是注解类的完整命名空间(如 App\Annotation\MyAnnotation),值是该注解的实例(object)。但注意:这个方法**不包含当前类名或方法名信息**,它只负责“把注解对象归集好”,位置信息得你自己从调用上下文里拿。
常见错误是以为调用完 AnnotationCollector::getAnnotationsByClass() 就能直接拿到被注解的方法名——其实不能。你得先知道“是谁在调用”,再反查它的反射信息。
在注解处理器中如何安全获取目标类名和方法名
Hyperf 的注解扫描发生在容器启动阶段,此时注解解析器(比如继承 AbstractAspect 或实现 AnnotationInterface)会收到一个 $className 和可选的 $methodName 参数。这才是真正可靠的来源。
- 如果是类级注解(如加在
class上),$methodName为null,$className是完整类名(如App\Controller\UserController) - 如果是方法级注解(如加在
public function index()上),$methodName是方法名(如"index"),$className同样是所在类的完整类名 - 不要试图在注解类的
__construct()或属性赋值时去反射当前上下文——那会失败,因为注解对象创建时上下文尚未绑定
想在运行时动态查某个类/方法是否被某注解标记,该用哪个方法
用 AnnotationCollector::getClassAnnotations() 或 AnnotationCollector::getMethodAnnotations(),它们才带上下文。
示例:检查 App\Service\OrderService::create() 是否有 @Log 注解:
// 注意:必须传入标准格式的类名 + 方法名
$annotations = AnnotationCollector::getMethodAnnotations(
'App\Service\OrderService',
'create'
);
if (isset($annotations['App\Annotation\Log'])) {
// 存在 @Log 注解
}
⚠️ 容易踩的坑:
- 类名必须是完整命名空间,不能是短名(
"OrderService"❌) - 方法名不能带括号(
"create()"❌) - 如果类未被 Hyperf 扫描过(比如没加
@Controller、@Service等触发扫描的注解),getMethodAnnotations()可能返回空数组,不是 bug,是扫描机制限制
为什么不用 ReflectionClass/ReflectionMethod 自己扫一遍
可以,但没必要,且容易和 Hyperf 的注解生命周期冲突。Hyperf 已在 DiCompilerPass 阶段完成全量扫描并缓存到 AnnotationCollector,直接读它更快、更稳。
自己用反射去重新解析,不仅重复劳动,还会绕过 Hyperf 对注解参数的类型转换(比如 @MyAnno(value="123") 中的 value 在 AnnotationCollector 里已是 int,而原始反射拿到的是字符串)。
真要调试注解是否生效,优先 dump AnnotationCollector::getAnnotationsByClass('App\Annotation\MyAnnotation') 看有没有实例;再确认对应类/方法是否出现在 AnnotationCollector::getClassList() 里。


















