hyperf 3.0 自定义注解必须使用#[attribute]声明,基于 php 8.1+ 原生 attributes,不再支持旧版@annotation风格;需指定作用域(如attribute::target_method)、通过构造函数参数接收值,并在aop切面中用getattributes()和newinstance()安全读取。

Hyperf 3.0 中自定义注解必须用 #[Attribute] 声明
Hyperf 3.0 基于 PHP 8.1+ 的原生 Attributes,不再支持旧版 @Annotation 风格。如果你沿用 Hyperf 2.x 的写法(比如继承 AbstractAnnotation),运行时会直接报错:Attribute class not found 或触发 ReflectionException。
正确做法是:定义一个普通类,加上 #[Attribute],并指定作用域(如 Attribute::TARGET_METHOD)。构造函数参数即为注解的“属性”,无需额外解析逻辑。
-
#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_CLASS)]—— 明确声明可用位置,否则默认只允许用于类 - 构造函数参数自动映射为注解调用时的命名参数,例如
#[MyAnnotation(name: "foo", enabled: true)] - 参数类型必须可被 PHP 反射识别(
string、int、bool、array、enum,或带#[Serializable]的类)
如何接收并验证构造函数参数
Hyperf 不干涉注解类本身的逻辑,所以参数校验、默认值、类型转换全靠你手动处理。别指望框架自动帮你做 isset 或 filter_var。
推荐在构造函数里做最小必要校验:
- 必填参数用类型声明 +
??提供默认值,例如public function __construct(public string $name, public bool $enabled = true) - 避免在构造函数里抛异常(PHP 层面限制),改用
assert()或记录 warning(尤其当参数来自用户输入时) - 若需复杂校验(如正则、长度),建议封装到 getter 方法中,比如
public function getValidatedName(): string { assert(strlen($this->name) name; }
在 AOP 切面中读取带参注解的值
Hyperf 的 Aspect 通过 ReflectionMethod 拿注解实例,再调用其属性或方法。注意:不能直接用 $method->getAttributes(MyAnnotation::class)[0]->name 就完事——得先检查数组非空,且确保返回的是你期望的注解类。
典型安全读取方式:
#[Aspect]
class MyAspect
{
#[PointExecution("App\Controller\*->*()")]
public function process(ProceedingJoinPoint $proceedingJoinPoint): mixed
{
$method = $proceedingJoinPoint->getMethod();
$attrs = $method->getAttributes(MyAnnotation::class);
if (!$attrs) {
return $proceedingJoinPoint->process();
}
$annotation = $attrs[0]->newInstance(); // 注意:这里触发构造函数重执行(若含副作用要小心)
$name = $annotation->name;
$enabled = $annotation->enabled;
if ($enabled) {
// 执行逻辑...
}
return $proceedingJoinPoint->process();
}
}
-
newInstance()是关键:它用当前注解声明时传入的参数重新实例化对象,不是从容器拿单例 - 如果注解类构造函数有副作用(如写日志、发 HTTP 请求),每次切面匹配都会触发,容易被忽略
- 不建议在
newInstance()后再做耗时操作,AOP 本身已影响性能
常见错误:参数名拼错、类型不匹配、未启用 Attribute 支持
最常卡住的地方其实是 PHP 配置和 IDE 提示断层:
- PHP 版本低于 8.1?
Attribute类根本不存在,报错Class "Attribute" not found - 注解类没加
#[Attribute],却在代码里写了#[MyAnnotation(...)]→ 运行时报Unknown attribute - 参数名大小写不一致,比如声明
public string $userName,但调用写成#[MyAnnotation(username: "a")]→ 参数被忽略,值为null或默认值 - IDE(如 PhpStorm)可能不识别自定义 Attribute,导致无补全、无跳转,但这不影响运行,别因此怀疑写法
Hyperf 3.0 的注解本质就是 PHP 原生 Attribute,没有魔法。参数是否生效,只取决于反射能否拿到实例、构造函数能否接受传入值、以及你的切面有没有正确调用 newInstance()。其余都是 PHP 语言层的事。











