hyperf 的 aop 切面不支持自动识别自定义注解,必须显式将注解类(如 mylog::class)写入切面的 $annotations 数组才能生效;注解需继承 attribute 并声明目标类型;切面类须加 #[aspect];获取注解参数需手动反射解析;应使用 getoriginalclassname() 而非 getclassname();多切面执行顺序不可控,建议合并处理。

Hyperf 的 AOP 切面本身不支持「自动识别自定义注解并触发装载」——必须显式声明目标,否则 process 方法根本不会被调用。
自定义注解必须手动注册到切面的 $annotations 数组中
Hyperf 的切面拦截机制只认你写死在 $annotations 里的类名,不会自动扫描项目里所有带某个注解的类。哪怕你用 #[MyLog] 标记了十个方法,只要没把它加进切面配置,就完全不会生效。
-
$annotations = [MyLog::class]是必须项,不能省略或留空 - 注解类本身需继承
Attribute,且至少声明Attribute::TARGET_METHOD | Attribute::TARGET_CLASS - 如果注解用了命名空间(比如
App\Annotation\MyLog),$annotations里也得写全路径 - 切面类必须带
#[Aspect],否则框架启动时直接忽略该类
ProceedingJoinPoint 里拿不到注解实例,得自己反射解析
Hyperf 的 ProceedingJoinPoint 提供了方法名、参数、类名等基本信息,但不提供当前被调用方法上的注解对象。想读取 @MyLog(level="debug") 这样的参数,得手动用 ReflectionMethod 去解析 PHPDoc 或 Attribute。
- 在
process方法里调用$point->getMethod()->getAttributes(MyLog::class)获取注解实例 - 注意:PHP 8.0+ 才支持
getAttributes();低版本需用phpdocumentor/reflection-docblock解析 DocBlock - 别直接依赖
$point->getClassName()做逻辑分支——它返回的是代理类名(如App\Service\UserService@proxy),要用$point->getOriginalClassName()
切面生效顺序不可控,多个切面叠加时容易覆盖行为
Hyperf 没有声明切面优先级的机制。当你同时启用日志切面、缓存切面、权限切面,它们都拦截同一个方法时,执行顺序取决于类文件在 aspects.php 里的注册顺序,或 PSR-4 自动扫描时的文件遍历顺序——这两者都不稳定。
- 不要在一个切面里做「调用前拦截 + 修改参数 + 调用后处理」这种强依赖流程,除非你能确保它是唯一切入该方法的切面
- 如果必须组合多个切面,建议合并成一个切面,在
process内部用条件判断分流,而不是靠多个独立切面协作 - 切面之间无法传递上下文(比如 A 切面设了个 flag,B 切面读不到),因为每个切面的
process是隔离执行的
真正麻烦的不是写切面,而是让切面「精准命中又不干扰其他逻辑」——尤其是当团队多人共用同一套注解时,没人会去翻每个切面的 $annotations 数组确认是否已注册。











