preg_replace 的 /e 模式自 php 5.5.0 起弃用、7.0.0 起彻底移除,无法通过配置禁用,必须替换为 preg_replace_callback;识别方法是搜索所有含 /e 修饰符的正则调用;安全替代方案是将原替换字符串中的 php 表达式移入回调函数,并注意捕获组引用、变量绑定及转义处理。

preg_replace 的 /e 模式不是“手动禁用”的功能,而是PHP 官方从 5.5.0 版本起正式弃用、7.0.0 版本起彻底移除的语言特性。它不存在开关或配置项让你“禁用”,而是:
一旦你使用的 PHP 版本 ≥ 7.0,带 /e 修饰符的 preg_replace 调用会直接报 致命错误(Fatal Error),无法运行;
在 5.5–5.6 和 7.0 之前的部分 7.x 早期版本(如 7.0.0~7.0.4),则会先触发 E_DEPRECATED 警告,再尝试执行(但极不稳定,不建议依赖)。
所以真正要做的不是“禁用 /e”,而是识别并替换掉所有含 /e 的旧代码。
怎么识别代码中是否用了 /e?
检查项目里所有 preg_replace 调用,重点看正则模式末尾是否有:
-
/e(最常见) -
/ei、/es、/eis等组合(e只要存在就触发弃用)
例如这些都违规:
preg_replace('/(w+)/e', 'strtoupper("\1")', $str);
preg_replace('/d+/ei', 'intval("\0") * 2', $str);
怎么安全替换成等效写法?
统一改用 preg_replace_callback,核心是把原来写在替换字符串里的 PHP 表达式,移到回调函数里执行。
- ✅ 基础替换(匿名函数):
// 旧写法(PHP
// 新写法(PHP ≥ 5.5,推荐) preg_replacecallback('/([A-Z])/', function($m) { return '' . strtolower($m[1]); }, $str);
- ✅ 类内方法调用(注意 `$this` 绑定):
```php
// 旧写法
preg_replace('/__(w+)__/e', '$this->parseTag("\1")', $str);
// 新写法(需 use 或绑定)
preg_replace_callback('/__(w+)__/', function($m) use ($this) {
return $this->parseTag($m[1]);
}, $str);
// 或写成数组形式:[$this, 'parseTag']
- ✅ 多捕获组 & 复杂逻辑(保持可读性):
preg_replace_callback( '/(d{4})-(d{2})-(d{2})/', function($m) { return sprintf('%s年%s月%s日', $m[1], $m[2], $m[3]); }, $dateStr );
为什么不能留着 /e 写法?
- 安全风险极高:
/e本质是eval(),若正则或替换内容受用户输入影响(如拼接$_GET参数),极易导致远程代码执行(RCE); - 兼容性断裂:PHP 7.0+ 直接报错终止脚本;
- 维护性差:逻辑混在字符串里,调试困难,IDE 无法语法提示或跳转。
快速迁移建议
- 全局搜索项目:
preg_replace(+/e或/e[imsx]* - 逐个替换为
preg_replace_callback,注意:- 去掉正则末尾的
e(只留i、s、m等合法修饰符) - 把原替换字符串中的
\1、\2改成$m[1]、$m[2]($m是回调函数参数) - 外部变量要用
use ($var)显式引入
- 去掉正则末尾的
- 替换后务必测试输出是否一致,尤其注意单引号/双引号、转义字符(如
'\1'→$m[1])
不复杂但容易忽略。











