PHP CS Fixer 不自动修复版本兼容性问题,需手动启用如 @PHP80Migration 等规则及 pow_to_exponentiation、array_syntax 等具体规则,并严格限定 Finder 范围排除 vendor 等目录,避免静默跳过或崩溃。
PHP CS Fixer 本身不“自动修复版本兼容性问题”,它只按你明确配置的规则去改代码;想让它把
换成
、把
换成
,必须主动启用对应规则——否则它默认只做 PSR-12 风格整理,完全不管 PHP 版本迁移。
怎么启用 PHP 8+ 语法升级规则
PHP CS Fixer 的版本兼容性修复能力藏在具体规则里,不是靠“选个 PHP 8.2 规则集”就能触发。比如:
:启用后会把
替换为
(仅当 PHP 8.0+ 环境下安全)、把
简化为
:启用后会把
改为
(仅当键非 null/数组时)
:启用后会把
替换为
(注意:这是保留原调用,但确保函数存在;实际是启用
类规则)
这些规则集不能单独使用,必须和基础规则合并。正确写法是:
为什么开了 @PHP80Migration 却没改任何代码
常见原因有三个,且 PhpStorm 或 CLI 都不会报错,只会静默跳过:
立即学习
“
PHP免费学习笔记(深入)
”;
PHP 8.5.5
PHP 8.5.5 是 PHP 8.5 分支的维护更新版本。该版本延续了“小步快跑”的迭代逻辑,通过深度错误修复、底层性能微调以及安全加固,旨在为开发者提供一个更健壮、更高效的运行环境。该版本严格遵守语义化版本规范,不包含破坏性变更。
下载
目标代码本身不匹配规则触发条件——比如
中的
只在有
语句且未使用时才删,空
不处理
PHP 解释器版本低于规则要求——
中部分规则依赖 PHP 8.1+ 的反射能力,若 PhpStorm 后台调用的是 PHP 7.4,规则直接被忽略
配置中未声明
且文件数超阈值——PHP CS Fixer v4 默认对单文件启用全部规则,但扫描整个
时若未显式启用并行或设置 finder 范围,部分迁移规则可能因性能策略被跳过
项目级配置文件必须排除 vendor 和测试桩
如果你在
里用了
但没 exclude
或
,会出现两种后果:
修复过程极慢,因为工具会尝试解析所有第三方包的源码(哪怕它们根本不用你的规则)
某些迁移规则(如
)遇到
里的老写法,可能因类型推断失败而崩溃,报
正确做法是严格限定范围:
CLI 执行时 --dry-run 不等于安全预览
只检查“是否需要改”,不验证“改了会不会破坏逻辑”。比如:
启用
后,它会强制给所有函数参数加类型声明,但如果原函数被动态调用(
),加了类型后运行时直接 fatal error
启用
会删掉
,但如果 Doctrine ORM 依赖这个注解生成 schema,删掉就导致 migration 失败
真正安全的做法是:
先用看改动,再挑关键文件手动验证行为,最后批量跑
。别信
的“0 files changed”提示——它只统计格式差异,不校验语义。
pow($a, 2)$a ** 2array()[]@PHP80Migrationis_countable()is_iterable()mb_strpos($s, '', 0, 'UTF-8')mb_strpos($s, '')@PHP81Migrationarray_key_exists($k, $arr)isset($arr[$k])@PHP82Migrationstr_starts_with()str_starts_with()modernize_str_*_functionsreturn PhpCsFixer\Config::create()
->setRules([
'@PSR12' => true,
'@PHP81Migration' => true,
'pow_to_exponentiation' => true, // 显式启用:把 pow($a, 2) → $a ** 2
'array_syntax' => ['syntax' => 'short'], // 把 array() → []
])
->setFinder($finder);@PHP80Migrationno_unused_importsuseuse@PHP81MigrationsetParallelConfig()src/.php-cs-fixer.phpin(__DIR__)vendortests/fixturesmodernize_types_castingvendor/symfony/consoleCannot process file: TypeError$finder = PhpCsFixer\Finder::create()
->in(__DIR__.'/src')
->in(__DIR__.'/app')
->in(__DIR__.'/config')
->name('*.php')
->notName('*.blade.php') // Laravel 模板跳过
->exclude('vendor')
->exclude('node_modules')
->exclude('tests/fixtures');php-cs-fixer fix --dry-runstrict_paramcall_user_func_arrayno_superfluous_phpdoc_tags@param string|null $id--diff--dry-run