编程 PHP 8.6 弃用 mb_ereg* 与 mb_split:Oniguruma 停更后怎么迁到 preg_*

2026-11-08 21:03:21

PHP 8.6 弃用 mb_ereg* 与 mb_split:Oniguruma 停更后怎么迁到 preg_*

Oniguruma 是 mbstring 扩展背后的正则引擎,2025 年 4 月结束维护。上游不再提供安全修复,PHP 无法继续把这条依赖链留在核心里,于是把整个 mbregex 层标记为弃用,PHP 9.0 移除。官方推荐的替代路径是带 /u 修饰符的 PCRE 函数。

受影响的函数

弃用范围覆盖 mbstring 正则接口的整组函数,不只是最常用的那两个:

  • 匹配:mb_ereg()、mb_eregi()、mb_ereg_match()
  • 替换:mb_ereg_replace()、mb_eregi_replace()、mb_ereg_replace_callback()
  • 搜索状态机:mb_ereg_search()、mb_ereg_search_init()、mb_ereg_search_pos()、mb_ereg_search_regs()、mb_ereg_search_getregs()、mb_ereg_search_getpos()、mb_ereg_search_setpos()
  • 拆分:mb_split()
  • 编码与选项:mb_regex_encoding()、mb_regex_set_options()

只要代码里还在调用这一组里的任意一个,8.6 下就会收到弃用提示。

迁到 preg_*:/u 与 \w 的差异

mb_ereg* 默认按 mbstring 的内部编码工作,编码由 mb_regex_encoding() 设置,通常是 UTF-8,因此按字符匹配。preg_* 默认按字节处理,要按 UTF-8 字符匹配必须显式加 /u。

// 旧写法
mb_regex_encoding('UTF-8');
$ok = mb_ereg('^\w+$', $name);

// 新写法
$ok = preg_match('/^\w+$/u', $name) === 1;

\w 在 PCRE 的 /u 下表示 Unicode 字母、数字和下划线,与 mb_ereg 的默认行为接近,但并非完全等价;涉及组合字符、连接符等边界情况时,需要用实际语料回归。

另一个必须处理的差异是返回值。无效 UTF-8 会让 preg_* 返回 false,而不是匹配失败:

preg_match('/^\w+$/u', "\xff");        // false
preg_last_error();                      // PREG_BAD_UTF8_ERROR

判断时用 === 1 / === false 区分「不匹配」和「出错」,不要只写 if (preg_match(...))。

替换侧还有一个历史包袱:mb_ereg_replace() 的 e 修饰符早已移除,而 preg_replace 的 /e 从 PHP 7 起也已移除。迁移中遇到的这类遗留写法要改写为 preg_replace_callback():

$out = preg_replace_callback(
    '/\{(\w+)\}/u',
    fn (array $m) => $vars[$m[1]] ?? '',
    $template
);

mb_onig PECL 包的位置

为依赖 mbregex 的存量代码准备了一个 PECL 包 mb_onig,把 Oniguruma 支持以扩展形式继续提供。它的作用是给迁移期一个缓冲,让老项目不必在一次升级中改完所有调用点,而不是长期方案。上游引擎本身已停止维护,安全修复跟不上,所以官方推荐仍然是迁到 preg_* + /u。

用静态检查把调用点找出来

先用一次全量扫描拿到清单,再决定是批量替换还是逐个看上下文:

rg -n '\b(mb_ereg\w*|mb_split|mb_regex_\w+)\s*\(' --glob '*.php'

把同样的规则固化成 CI 检查,PHPStan 自定义 Rule、PHP_CodeSniffer 的自定义 sniff 都能做,核心是匹配上述函数名并在新代码合入时拦截。扫描结果里要特别注意两类:一是 mb_ereg_replace 带选项参数的调用,二是 mb_ereg_search_* 这种分步调用状态机的写法,它们不能机械替换,需要重写成 preg_match + $matches。

同一版本里的另外两个弃用

  • php://filter 过滤器链上限为 16。未配置 filter.max_filter_count 时超限发 E_DEPRECATED;显式配置后超限直接打开失败,属于行为变化而非仅提示。
  • __construct() / __destruct() 的返回值弃用。检测到 return 就发弃用提示,PHP 9.0 变为错误。

按已公布的排期,8.6 的 GA 在 2026-11-19,正式发版前还有若干 RC。弃用项在 8.x 内只是提示,9.0 才真正移除,但 mb_ereg* 的替换越早做越好,因为语义差异需要靠测试兜住,而不是靠改函数名。

参考

复制全文 生成海报 PHP 正则 升级踩坑

推荐文章

程序员茄子在线接单