不能。php 原生 #[attribute] 不支持 @deprecated docblock 触发运行时警告,hyperf 3.x 注解系统仅通过反射读取 attribute 实例,忽略所有 docblock;唯一有效方式是在构造函数中调用 trigger_error(e_user_deprecated)。

Hyperf 3.x 中的注解类还能用 @deprecated 吗
不能。PHP 原生 #[Attribute] 不支持在 Attribute 类上直接使用 @deprecated DocBlock 标记来触发运行时警告——这种注释对反射读取、AOP 切面或容器扫描完全无影响,也不会在调用处报 Deprecated: 提示。
为什么 @deprecated 在注解类里失效
Hyperf 3.x 的注解系统只通过 ReflectionMethod::getAttributes() 拿到实例,而 PHP 的 @deprecated 是编译器/IDE 层提示机制,不参与运行时反射流程。即使你在 #[Inject] 类顶部写 /** @deprecated use #[AutoInject] instead */,框架照样加载、执行,用户也看不到任何警告。
- PHP 本身不解析
@deprecated注释用于 Attributes 生命周期控制 - Hyperf 的扫描器(
Hyperf\Di\Annotation\Scanner)只认#[Attribute]实例,忽略所有 DocBlock 内容 - IDE(如 PhpStorm)可能识别并标黄,但 CLI 启动、HTTP 请求、AOP 拦截均不受影响
真正有效的废弃方案:用 trigger_error() + 构造函数拦截
想让旧注解在被实际使用时发出弃用警告,唯一可靠方式是在其构造函数中主动触发错误:
#[Attribute(Attribute::TARGET_PARAMETER | Attribute::TARGET_PROPERTY)]
class Inject
{
public function __construct(public string $name = '')
{
trigger_error('Inject is deprecated, use #[AutoInject] or constructor type-hinting instead.', E_USER_DEPRECATED);
// 其余逻辑保持不变
}
}
- 必须放在构造函数内,不能放静态方法或 getter 中——因为
$attr->newInstance()才会调用它 - 用
E_USER_DEPRECATED而非E_USER_WARNING,确保与 PHP 自身弃用警告一致 - 注意:若该注解被大量用于 trait 或父类,警告会高频触发,建议加简单缓存(如
static $warned = false; if (!$warned) { ... $warned = true; })
配合迁移的硬性收尾动作
仅加 trigger_error 不够,用户很可能忽略警告继续用。必须同步做三件事:
- 在
config/autoload/annotations.php的ignore_annotations里显式列出旧注解类名(如'Inject'),阻止其被扫描器处理(否则仍会注册、冲突) - 更新 IDE stubs 或 PHPStan 配置,把旧注解类标记为
@deprecated并排除类型检查 - 在 CI 流程中加
grep -r "@deprecated" app/ --include="*.php" | grep -v "E_USER_DEPRECATED"类似检查,防止遗漏构造函数警告
最易被忽略的是:ignore_annotations 只接受类名字符串(不含命名空间),且大小写敏感;写成 'Hyperf\Di\Annotation\Inject' 或 'inject' 都无效。











