PHP 7.4 起棄用 preg_replace 的 /e 修飾符,PHP 8.0 完全移除。舊代碼 preg_replace('#{([a-z_0-9]+)}#Uei', "\$data[\1]", $str) 必須重寫。本文詳細拆解遷移步驟與陷阱。
| 特性 | preg_replace (舊) | preg_replace_callback (新) |
|---|---|---|
| 回調方式 | 字符串代碼 \$data[\1] | Closure/可調用對象 |
| 變量作用域 | 自動提取 $1 到字符串 | 通過 $matches 數組訪問 |
| 安全性 | 極低(任意代碼執行風險) | 高(受函數作用域限制) |
| 性能 | 每次匹配 eval | 僅調用函數,極快 |
$pattern = '#\{([a-z_0-9]+)\}#Uei'; // 保持原修飾符
$callback = function ($matches) use ($data) {
$key = $matches[1]; // $matches[0] 整個匹配,[1] 第一個捕獲組
return isset($data[$key]) ? $data[$key] : $matches[0]; // 找不到保留原樣
};
$result = preg_replace_callback($pattern, $callback, $data['setting']['url']['list']);
$matches[1] 對應正則中第一個 (),舊寫法 \1 現在不可用。use ($data) 將外部數組引入閉包,否則作用域不可见。U(非貪婪)、e(已棄用)、i(忽略大小寫)需視業務調整,建議顯式聲明 #Uiu(Unicode)。null 會轉為空串。高頻調用時,將正則編譯結果緩存:
static $compiled = null;
if ($compiled === null) $compiled = '#\{([a-z_0-9]+)\}#Uiu';
return preg_replace_callback($compiled, $callback, $subject);
遷移完成後,代碼更安全、可讀、可維護,且兼容 PHP 8.1+。