#[Deprecated]仅支持类、方法、属性、类常量、函数、参数六类命名空间作用域声明,不支持define()定义的全局常量或嵌套在控制结构中的函数;需配合trigger_error()等运行时触发及PHPStan等工具扫描才能生效。
![php 8.5.7 的 #[\deprecated]注解妙用【代码自文档化】](https://img.php.cn/upload/article/001/503/042/178376802538131.png)
PHP 8.5.7 中 #[Deprecated] 能用在哪些地方?
它不能用在任意位置——只支持类、方法、属性、类常量、函数、参数这六类声明,且必须是命名空间作用域下的 const 或 function,不支持 define() 定义的全局常量或闭包内定义的函数。
常见误用场景:
- 给
define('LEGACY_MODE', 1)加 #[Deprecated] → 无效,PHP 解析时直接忽略 - 在
if块里写#[Deprecated] function foo() {}→ 报语法错误,注解必须紧邻声明,且不能嵌套在控制结构中 - 为 trait 中未实现的抽象方法加 #[Deprecated] → 不触发警告,因该方法本身无运行时入口
怎么让 #[Deprecated] 真正生效并被 IDE / 工具识别?
光加注解不够,必须配合运行时触发或静态分析工具才能形成闭环。PHP 自身不会自动拦截调用,它只提供元数据,是否警告由你控制。
推荐做法:
立即学习“PHP免费学习笔记(深入)”;
- 对函数:在函数体开头加
trigger_error(..., E_USER_DEPRECATED),否则调用时无声无息 - 对类方法:优先走
__call()或代理层拦截,避免直接暴露废弃方法 - 对类常量:改用私有常量 + 静态 getter(如
getLegacyTimeout()),并在 getter 内触发警告 - 使用 PHPStan 或 Psalm 扫描时,需启用
phpstan/extension-installer和phpstan-deprecation-rules插件,否则注解会被跳过
#[Deprecated] 的 message 和 since 参数怎么填才实用?
填空式写法(如 message: "don't use this")对协作毫无帮助;真正有用的字段要指向迁移路径和时间锚点。
有效写法示例:
#[Deprecated(
message: "Use Config::TIMEOUT_MS (int ms) instead of Config::LEGACY_TIMEOUT (int s).",
since: "8.4"
)]
关键点:
-
since建议统一用 PHP 主版本号(如"8.4"),不要写"v2.0"或日期,PHP 内部弃用机制也这么用 -
message必须含替代方案,最好带类型提示(int msvsint s)和命名差异 - 避免模糊表述:“This will be removed soon” → 改成 “Will be removed in next major release (v3.0)”
为什么有些 #[Deprecated] 在 PHP 8.5.7 下没报错也没警告?
因为 PHP 8.5.7 本身不执行任何拦截逻辑——它只是把注解存进反射信息,是否触发警告完全取决于你有没有主动读取并响应它。
典型静默原因:
- 没调用
trigger_error(),也没在 autoloader 或 proxy 层做检查 - IDE(如 PhpStorm)未启用 “Show deprecated API usage” 检查项
- PHPStan 默认不启用弃用规则,需手动加
phpstan.neon配置:includes: [vendor/phpstan/deprecation-rules/rules.neon] - Composer autoload 未加载注解类(
class Deprecated extends Attribute),导致反射读取失败
最易被忽略的一点:#[Deprecated] 是 PHP 8.4 引入的,PHP 8.5.7 只是延续支持;如果你项目还混着 PHP 8.3 的构建环境,注解会直接被当成非法语法报错,而不是静默失效。



















