必须用#[attribute(attribute::target_property)]显式授权属性目标,否则运行时报错;读取需用reflectionproperty而非reflectionclass;构造参数须严格匹配定义且不可含变量或运行时逻辑。

在类属性上使用 #[Attribute] 需显式声明 TARGET_PROPERTY
PHP 不会自动把注解识别为“可用于属性”,哪怕你把它写在 $property 上方。必须在注解类定义时用 #[Attribute(Attribute::TARGET_PROPERTY)] 明确授权,否则运行时报错:Fatal error: Attribute "MyAttribute" cannot target property。
常见错误是直接套用方法级注解的写法,比如复制 #[Attribute(Attribute::TARGET_METHOD)],结果属性上加了注解却读不到 —— 反射调用 $reflectionProperty->getAttributes() 返回空数组。
- 只允许用于属性:用
#[Attribute(Attribute::TARGET_PROPERTY)] - 同时支持属性和方法:用
#[Attribute(Attribute::TARGET_PROPERTY | Attribute::TARGET_METHOD)] - 若需多次标注同一属性(如多个验证规则),必须加
Attribute::IS_REPEATABLE
读取属性注解要用 ReflectionProperty,不是 ReflectionClass
很多人习惯从类反射对象出发,调用 $refClass->getAttributes(),但这只能拿到类级注解;属性上的注解必须单独获取对应属性的反射实例。
正确路径是:先用 $refClass->getProperty('name') 拿到 ReflectionProperty 对象,再在其上调用 getAttributes()。
- 错误写法:
$classRef->getAttributes(MyValidation::class)→ 返回空 - 正确写法:
$propRef = $classRef->getProperty('email'); $propRef->getAttributes(MyValidation::class) - 如果属性是
private,记得先调用$propRef->setAccessible(true),否则反射无法访问值
构造参数传值语法要匹配注解类定义
注解不是注释,它本质是类实例化过程的语法糖。括号里写的每个值,都会原样传给注解类的 __construct(),顺序或命名必须严格对齐。
比如注解类定义为 public function __construct(public string $rule, public ?int $max = null),那么下面三种写法中只有前两种合法:
-
#[MyValidation("required")]→ OK,按顺序传参 -
#[MyValidation(rule: "email", max: 255)]→ OK,命名参数,顺序无关 -
#[MyValidation("email", 255, true)]→ 报错,构造函数只有两个参数
注意:参数不能是变量或表达式,#[MyValidation($allowed)] 或 #[MyValidation(ENV === 'dev')] 都会触发解析失败。
注解类本身不能依赖运行时状态
注解在编译/加载阶段就被解析并固化,newInstance() 调用时不会执行任何外部逻辑(比如数据库查询、配置读取)。所有数据必须在写注解时就确定好。
这意味着你不能在注解类的 __construct() 里做 file_get_contents()、调用 config('db.host'),也不能试图在构造函数里 throw 异常来拦截非法值 —— PHP 解析器根本不会执行它。
真正校验参数合法性,得靠框架层或自定义扫描器在反射后手动检查,例如:
foreach ($attributes as $attr) {
$instance = $attr->newInstance();
if (!in_array($instance->rule, ['required', 'email', 'url'])) {
throw new InvalidArgumentException("Invalid rule: {$instance->rule}");
}
}
这个限制常被忽略:以为注解类能像普通类一样自由编码,实际它只是个带约束的“数据容器”。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











