ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

PHP-CS-Fixer `ereg_to_preg` 规则详解:将废弃的 ereg 系列正则函数安全迁移到 PCRE

PHP-CS-Fixer `ereg_to_preg` 规则详解:将废弃的 ereg 系列正则函数安全迁移到 PCRE 开发工具代码质量静态分析Lint格式化【免费下载链接】PHP-CS-FixerA tool to automatically fix PHP Coding Standards issues项目地址https://gitcode.com/gh_mirrors/ph/PHP-CS-Fixer点击查看免费下载导读ereg_to_preg是 PHP-CS-Fixer 中一条用于将 PHP 5.3 之前引入、早已废弃的 POSIX 风格正则函数ereg、eregi、ereg_replace、eregi_replace、split、spliti自动改写为 PCRE 风格函数preg_match、preg_replace、preg_split的修复规则。本文基于该规则在 PHP-CS-Fixer 仓库中的官方文档、Fixer 源码与测试用例完整讲解它转换的函数映射、定界符选择策略、D修饰符的语义、风险边界以及启用方式帮助你安全地在存量代码库中完成这次现代化迁移。规则概述一条解决废弃函数迁移的 Risky 规则PHP 自 5.3.0 起将ereg系列函数标记为废弃并在 PHP 7.0 中彻底移除ext/ereg扩展被删除。任何运行在现代 PHP 版本上的历史代码只要还调用ereg、split等函数都会直接触发致命错误。ereg_to_preg规则的目标就是自动把这些调用替换为等价的preg系列函数调用让旧代码可以在新版本 PHP 上继续运行。在 PHP-CS-Fixer 的规则文档 doc/rules/alias/ereg_to_preg.rst 中该规则被定义为Replace deprecatederegregular expression functions withpreg.同时文档明确标注了一条WarningThis rule isRISKY— Risky if theeregfunction is overridden.也就是说如果项目代码中通过function ereg(...)自行定义覆盖了与ereg同名的函数或者通过命名空间use导入了同名函数那么这条规则的重写会改变程序的实际行为因此它被归类为 Risky 规则默认不会被普通的非 Risky 规则集启用。函数映射表六个旧函数 → 三个 PCRE 函数从 Fixer 源码 src/Fixer/Alias/EregToPregFixer.php 可以看到规则内部维护了一张完整的映射表FUNCTIONS常量这也是整条规则转换行为的事实基础旧函数POSIX 正则已移除新函数PCRE追加修饰符语义对应ereg($pattern, $subject)preg_match无匹配大小写敏感eregi($pattern, $subject)preg_matchi匹配大小写不敏感ereg_replace($pattern, $replacement, $subject)preg_replace无替换大小写敏感eregi_replace($pattern, $replacement, $subject)preg_replacei替换大小写不敏感split($pattern, $subject)preg_split无分割大小写敏感spliti($pattern, $subject)preg_spliti分割大小写不敏感映射逻辑非常直观大小写不敏感的i变体eregi、eregi_replace、spliti会被转换为其对应 PCRE 函数并在模式末尾追加i修饰符从而保留原有的不区分大小写语义参数顺序在两个函数族之间保持完全一致模式在前、subject 在后*_replace的 replacement 位置也一致因此转换是机械且一一对应的。关键设计自动追加D修饰符在 applyFix 方法 中构造 PCRE 模式时使用了$preg $delim.addcslashes($string, $delim).$delim.D.$map[2];即在模式闭合定界符之后、原有映射修饰符i之前固定追加D修饰符。这是本次迁移中非常关键的一个语义对齐点POSIX 的ereg语义中$只匹配字符串的绝对末尾PCRE 默认情况下$除了匹配末尾外还会匹配末尾换行符之前的位置追加D修饰符后PCRE 的$被限制为只匹配字符串最末尾从而与旧ereg的行为保持一致避免引入微妙的匹配结果差异。这也是为什么示例输出是/[A-Z]/D而不是简单的/[A-Z]/的原因。转换示例规则文档 doc/rules/alias/ereg_to_preg.rst 给出了官方示例--- Original New -?php $x ereg([A-Z]); ?php $x preg_match(/[A-Z]/D);测试用例 tests/Fixer/Alias/EregToPregFixerTest.php 则提供了远比文档更丰富的行为样本可以看作官方承诺的完整行为契约// eregi → preg_match i 修饰符 ?php $x preg_match(/[A-Z]/Di, $m); // 来自 eregi([A-Z], $m) // ereg_replace → preg_replace ?php $x preg_replace(/[A-Z]/D, , $m); // 来自 ereg_replace([A-Z], , $m) // eregi_replace → preg_replace i ?php $x preg_replace(/[A-Z]/Di, , $m); // 来自 eregi_replace([A-Z], , $m) // split → preg_split ?php $x preg_split(/[A-Z]/D, $m); // 来自 split([A-Z], $m) // spliti → preg_split i ?php $x preg_split(/[A-Z]/Di, $m); // 来自 spliti([A-Z], $m) // 二进制字符串前缀 b/B 会被原样保留 ?php $x preg_split(b/[A-Z]/Di, $m); // 来自 spliti(b[A-Z], $m) ?php $x preg_split(B/[A-Z]/Di, $m); // 来自 spliti(B[A-Z], $m)定界符选择策略最小转义优先PCRE 要求模式必须被一对定界符包围文档默认推荐/也支持#、!等。由于旧ereg模式中不含任何定界符转换时必须为每个模式挑选一个不会与模式内容冲突的定界符。Fixer 源码通过 getBestDelimiter 方法 实现了最小转义优先策略候选定界符按偏好顺序排列/、#、!见 DELIMITERS 常量依次检查模式字符串中是否包含该字符只要找到第一个未在模式中出现的定界符立即选用它——这样模式内容完全无需转义如果三个候选定界符都出现在模式中则统计各定界符在模式中的出现次数选择出现次数最少者次数相同时按候选顺序取前者并把选中的定界符在模式内通过addcslashes全部转义。测试用例对这一策略给出了直观验证// 模式含 /自动改用 # 作定界符无需转义 ?php $x preg_match(#/[AZ]#D, $m); // 来自 ereg(/[AZ], $m) // 模式含 / 和 #改用 !并转义 ! 与 / ?php $x preg_match(!##[A\!]//!D, $m); // 来自 ereg(##[A!]//, $m) // 三个定界符全部出现时选择出现次数最少的 / 并做转义 ?php $x preg_match(/##[A!!]\/\//D, $m); // 来自 ereg(##[A!!]//, $m)可以看到无论模式内容如何刁钻同时包含/、#、!规则都能选出代价最小的定界符方案保证转换后的模式仍然合法可运行。安全机制三重守卫确保转换正确ereg_to_preg并非无脑的字符串替换源码中内置了三重守卫只有全部通过才会执行改写守卫一必须是全局函数调用规则通过 FunctionsAnalyzer::isGlobalFunctionCall 判断目标T_STRING是否确实是对全局命名空间函数的调用。以下情况都会被跳过与 测试用例 一一对应?php $x Foo::split([A-Z], $m); // 静态方法调用不转换 ?php $x $foo-split([A-Z], $m); // 实例方法调用不转换 ?php $x Foo\split([A-Z], $m); // 命名空间函数调用不转换这一守卫正是文档 Warning 中 Risky if theeregfunction is overridden 的源码级体现如果项目用命名空间导入或自定义了同名函数规则不会误伤它们。守卫二第一个参数必须是完整字符串字面量规则只处理第一个参数为单个字符串字面量的调用源码中 检查下一个有意义 token 是否为,或)。遇到拼接等复杂表达式时会直接跳过?php $x ereg([A-Z].foo, $m); // 字符串拼接无法安全转换跳过守卫三转换后的 PCRE 必须通过实际校验在改写 token 之前规则会调用 checkPreg 方法 通过项目自带的 Preg 类 对生成的模式执行一次真实的preg_match试运行如果模式非法例如ereg(^*broken, $m)这种在 PCRE 下无法编译的模式规则会跳过该调用而不是生成一个运行时才会报错的坏代码。规则的执行优先级与生效规则集与其他规则的协作顺序从 getPriority 方法 的注释可以看到该规则声明了Must run after NoUselessConcatOperatorFixer优先级为0。也就是说在修复流水线中no_useless_concat_operator会先于ereg_to_preg运行——这保证了字符串拼接类表达式在进入本规则时已经尽可能被规整为单一字面量扩大可转换范围。所属规则集规则文档列出了两条包含该规则的 Risky 规则集PhpCsFixer:risky在源码 src/RuleSet/Sets/PhpCsFixerRiskySet.php 中该规则集通过Symfony:risky间接引入ereg_to_preg其getRules()首行即包含Symfony:risky true对应文档 doc/ruleSets/PhpCsFixerRisky.rstSymfony:risky在源码 src/RuleSet/Sets/SymfonyRiskySet.php 中直接声明ereg_to_preg true对应文档 doc/ruleSets/SymfonyRisky.rst。因此在.php-cs-fixer.dist.php配置中使用Symfony:risky true或PhpCsFixer:risky true即可自动启用这条规则也可以按需单独启用?php // .php-cs-fixer.dist.php return (new PhpCsFixer\Config()) -setRules([ Symfony:risky true, // 集合方式随 Symfony 风格 Risky 集启用 // 或者单独启用 ereg_to_preg true, ]) -setFinder(PhpCsFixer\Finder::create()-in(__DIR__));使用建议与注意事项启用前先排查同名函数由于规则是 Risky 的建议先在项目中全局搜索function ereg、function split等自定义定义以及use function ereg;之类的导入语句确认不存在覆盖后才放心启用。前述FunctionsAnalyzer守卫能拦截大部分非全局调用场景但全局命名空间内的同名函数覆盖仍需人工确认。配合修复命令使用可通过php-cs-fixer fix path/to/code --rulesereg_to_preg单独针对该规则运行或--dry-run --diff先预览将要产生的改动再落地。语义对齐已被测试锁定D修饰符、i修饰符、定界符选择、二进制字符串前缀保留等行为全部被 EregToPregFixerTest 的测试用例锁定文档明确指出该测试类定义了官方支持的行为且每个测试用例都是向后兼容承诺的一部分升级 PHP-CS-Fixer 时行为稳定性有保障。小结ereg_to_preg是一条小而精的迁移型 Risky 规则它把 6 个已被 PHP 移除的 POSIX 正则函数机械地映射为 3 个等价的 PCRE 函数并通过D修饰符对齐$语义、通过最小转义定界符策略保证模式合法性、通过三重守卫全局函数判定、字面量参数判定、PCRE 实际校验把误转换风险降到最低。对于仍在维护的历史代码库在确认无同名函数覆盖的前提下通过Symfony:risky或PhpCsFixer:risky规则集启用它是向现代 PHP 迁移低成本且高收益的一步。赞分享开发工具代码质量静态分析Lint格式化【免费下载链接】PHP-CS-FixerA tool to automatically fix PHP Coding Standards issues项目地址https://gitcode.com/gh_mirrors/ph/PHP-CS-Fixer点击查看免费下载相关推荐PHP-CS-Fixer 规则集 PHP70MigrationPHP 7.0 兼容性规则与废弃迁移指南PHP CS Fixer 规则集 PHP70Migration PHP 7.0 兼容性规则与废弃迁移指南 PHP70Migration 是 PHP CS开发工具代码质量静态分析Lint格式化PHP-CS-Fixer 规则集详解从弃用的 PER-CS1.0 迁移到 PER-CS1x0PHP CS Fixer 规则集详解从弃用的 PER CS1.0 迁移到 PER CS1x0 导读 本文以 PHP CS Fixer 官方规则集文档 do开发工具代码质量静态分析Lint格式化Feather框架革命性同步Rust Web框架告别async/await的复杂性Feather框架革命性同步Rust Web框架告别async/await的复杂性 Feather框架是一个革命性的同步Rust Web框架它通过创新的同开发工具代码质量静态分析Lint格式化创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表