字串處理是 PHP 開發高頻操作。strstr、strrchr、strtr 三個函式雖然名稱相似,但用途截然不同。本文系統解析其語法、行為差異、多位元組 (mbstring) 對應版本、實戰陷阱與最佳實踐。
// 語法 strstr(string $haystack, string $needle, bool $before_needle = false): string|false // 核心行為 $email = 'user@example.com'; echo strstr($email, '@'); // @example.com (預設返回 needle 及其後) echo strstr($email, '@', true); // user (PHP 5.3+ $before_needle=true 返回 needle 前) // 大小寫不敏感版本 echo stristr($email, 'EXAMPLE'); // @example.com // 多位元組安全版本 (需 mbstring 擴展) $zh = '你好世界,PHP'; echo mb_strstr($zh, '世界', false, 'UTF-8'); // 世界,PHP echo mb_strstr($zh, '世界', true, 'UTF-8'); // 你好 // 關鍵點 // - 返回 false 若未找到 (嚴格比較 === false) // - 二進制安全,可處理 \0 // - 僅搜尋字串,若 needle 為整數則視為字元 ASCII 碼 (不推薦,易混淆) // - 效能:若僅需判斷是否存在,用 strpos() 更快、更省記憶體
// 語法
strrchr(string $haystack, string $needle): string|false
// 核心差異:從右向左搜尋
$path = '/var/www/html/index.php';
echo strrchr($path, '/'); // /index.php (最後一個 / 及其後)
// 多位元組版本
echo mb_strrchr($zh, '界', false, 'UTF-8'); // 界,PHP
echo mb_strrchr($zh, '界', true, 'UTF-8'); // 你好世
// 常見用途:獲取副檔名
function getExtension(string $filename): string {
$ext = strrchr($filename, '.');
return $ext ? substr($ext, 1) : '';
}
echo getExtension('archive.tar.gz'); // gz (只取最後一個 . 後)
// 兩種呼叫模式
// 模式一:字元對字元映射 (長度必須相等)
echo strtr('Hilla Warld', 'ia', 'eo'); // Hello World
// 'i'->'e', 'a'->'o',逐字元替換,不會產生鏈式替換問題
// 模式二:關聯陣列映射 (子串替換,支援不同長度,長者優先)
$trans = [
'Hello' => 'Hi',
'world' => 'earth',
'Hi' => 'Hey', // 不會被上一條 'Hello'->'Hi' 影響,因 strtr 掃描一次完成
];
echo strtr('Hello world', $trans); // Hi earth
// 關鍵特性:單次掃描、無重疊替換、長子串優先
// 對比 str_replace:str_replace 循序執行,可能產生鏈式替換
$arr = ['a' => 'b', 'b' => 'c'];
echo str_replace(array_keys($arr), array_values($arr), 'a'); // c (a->b->c)
echo strtr('a', $arr); // b (單次掃描,a 直接變 b)
// 多位元組支援:strtr 本身支援多位元組字串 (按位元組操作但 UTF-8 相容)
// 複雜多位元組替換建議用 mb_ereg_replace / preg_replace (u 修飾符)
| 函式 | 用途 | 搜尋方向 | 返回值 | 多位元組版本 | 典型場景 |
|---|---|---|---|---|---|
| strstr | 首次出現後段 | 左→右 | 子串/false | mb_strstr | Email 域名提取、前綴判斷 |
| stristr | 不分大小寫 strstr | 左→右 | 子串/false | 無 (用 mb_stristr 或 mb_strtolower+mb_strstr) | 關鍵字過濾 |
| strrchr | 最後一次出現後段 | 右→左 | 子串/false | mb_strrchr | 副檔名、路徑檔名分離 |
| strtr | 字元/子串映射替換 | 單次掃描 | 新字串 | 原生支援 | 模板引擎、字元正規化、編碼轉換 |
| str_replace | 子串替換 (循序) | 左→右循序 | 新字串/計數 | 原生支援 | 簡單替換、批次關鍵字替換 |
=== false 判斷失敗,if (strstr(...)) 會誤判 "0" 為失敗。strtolower('İ') (土耳其語點式 I) 在預設 locale 下異常,多語言環境必須用 mb_strtolower($str, 'UTF-8')。strtr 陣列模式對大量替換 (數萬對) 效能遠優於 str_replace,但對少量替換 str_replace 更快 (C 層優化)。mbstring.func_overload (PHP 8.2 已移除) 或手動調用 mb_strpos、mb_substr 等,確保 UTF-8 正確性。preg_replace('/pattern/u', $replacement, $subject) 支援 Unicode 屬性、前瞻後顧、回調函式。league/plates、twig/twig、bladeone,而非手寫 strtr。pathinfo()、parse_url()、SplFileInfo、League\Uri。理解字串函式的語義邊界、編碼敏感度、效能特徵,是寫出正確、高效、可維護 PHP 代碼的基本功。