必须加 php -d error_reporting=E_ALL 才能暴露所有 deprecated 警告,因 PHP 默认不显示;Composer 不触发警告,而是 PHP 解析 vendor 代码时抛出,需配合 display_errors=1 和 --no-ansi -v 在 CI 中确保日志可见。

怎么让 PHP 运行时暴露所有 deprecated 警告
不打开 E_DEPRECATED,你永远看不到哪个依赖在偷偷调用 mysql_connect() 或 each()。Composer 本身不触发这些警告,是 PHP 解析器在执行 vendor 代码时抛出的——但默认不显示。
- 本地复现:在命令前加
php -d error_reporting=E_ALL -d display_errors=1,例如php -d error_reporting=E_ALL artisan tinker - CI 流水线:必须加
--no-ansi -v(对 Composer 命令)+php -d error_reporting=E_ALL(对测试/启动命令),否则日志里根本没线索 - 别信
php.ini里的全局设置——有些框架(如 Laravel)会覆盖它,入口文件顶部的error_reporting(-1)才是真实生效点 - PHP 8.2+ 默认禁用
get_magic_quotes_gpc,但如果你没看到警告,大概率是error_reporting没包含E_DEPRECATED
如何快速定位是哪个包在调用废弃函数
警告里带路径就直接锁定问题包;不带路径?得靠组合命令交叉验证,不能只看终端一闪而过的黄色文字。
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
- 有文件路径(如
in /vendor/old-lib/src/Util.php on line 45):运行composer show old-lib查当前版本,再跑composer show -a old-lib看abandoned字段 - 无路径但含类名/方法名(如
Package::getNames() is deprecated):大概率是 Composer 插件或旧版插件 API,先试composer update --no-plugins - 警告只出现在
composer update -v末尾:说明是 Packagist 元数据里的abandoned标记,不是运行时问题,用composer audit --abandoned确认 - 不确定是否真加载了该类:查 autoload 映射
grep -r "class OldUtil" vendor/composer/autoload_classmap.php,避免误判残留文件
替换废弃包时最常踩的三个断裂点
光改 composer.json 和 composer remove 不够,新旧包之间往往存在隐性断层,运行时才爆。
- 命名空间变更:比如从
use MonologLogger切到use MonologHandlerStreamHandler,但旧代码里还写new Logger()—— 全局搜new Logger和use Monolog\才能扫干净 - 构造参数签名不兼容:新包可能把
__construct(array $config)改成__construct(HandlerStack $handler, array $config = []),漏掉类型声明或默认值就会 fatal error - autoload 配置差异:旧包用
psr-0,新包只支持psr-4且根命名空间变了,composer dump-autoload -o后必须跑单元测试,否则Class not found会在第一次请求时才出现
为什么 grep + php -l 仍是最快的手动扫描组合
静态分析工具(PHPStan/PSALM)适合查类型和逻辑,但对废弃函数这种“语法合法但语义过时”的问题,简单文本匹配反而更准、更快、更可控。
- 查具体函数:用
grep -r "create_function(" --include="*.php" vendor/,限定后缀避免扫到 .md 或 .json - 查模糊模式:废弃函数常被封装,比如
mcrypt_encrypt可能藏在call_user_func('mcrypt_encrypt', ...)里,用grep -r "mcrypt_" --include="*.php" vendor/更保险 - 排除干扰:有些包把测试文件放在
tests/下,但它们不会进生产 autoload,加--exclude-dir=tests避免误报 - 性能注意:大项目里全量
grep -r可能卡几秒,加--max-depth=3限制层级,通常 src/ 和 lib/ 才是重点
each(),而是确认这个调用来自你控制的代码,还是某个深埋在三级依赖里的老 SDK —— 后者往往要等 composer depends --tree old/sdk 跑完,才看清谁在拖后腿。

















