PHP 性能優化 42 條鐵律:從語法細節到架構層面的完整清單
整理自經典優化建議並結合現代 PHP 實踐補充。涵蓋語法、函數選擇、記憶體、資料庫、緩存、Web Server 等維度,每條附帶原理說明與代碼對比。
語法與語言特性(1-14)
- 能 static 就 static:靜態方法調用無需實例化,速度提升 ~4 倍。
- echo > print:echo 是語言結構,print 是函數且有返回值,echo 更快。
- echo 多參數 > 字串連接:
echo 'a', 'b' 避免中間字串分配,比 echo 'a'.'b' 快。
- 循環前計算最大值:
$max = count($arr); for($i=0;$i<$max;$i++) 避免每次呼叫 count()。
- 及時 unset 大變數:釋放記憶體,特別是大陣列/物件。
- 避免魔術方法:
__get/__set/__autoload 觸發開銷大,改用顯式存取器。
- 少用 require_once:檢查已包含檔案有開銷,明確依賴用
require,配合 Composer 自動載入(類映射/PSR-4)最優。
- 包含檔案用絕對路徑:減少路徑解析開銷,
__DIR__ . '/config.php'。
- 用 $_SERVER['REQUEST_TIME'] 替代 time():避免系統調用,精度足夠。
- 字串處理優先用 str_* 函數:
strncasecmp, strpbrk, stripos 比正則快得多。
- strtr > str_replace > preg_replace:
strtr 速度是 str_replace 4 倍,正則最慢。
- 字串替換參數為單字元時,寫多行替換:避免陣列建立與遍歷開銷。
- switch > 多重 if-else:跳躍表優化,可讀性也更好。
- 禁用 @ 抑制錯誤:極其低效,改用正確的錯誤處理(try-catch、isset 檢查)。
變數與記憶體(15-24)
- 啟用 Apache mod_deflate:壓縮傳輸體積,降低 80% 頻寬。
- 資料庫連線用完即關:避免連線洩漏佔用資源。
- $row['id'] > $row[id]:字串鍵需加引號,否則 PHP 先當常數查找再轉字串,慢 7 倍。
- 錯誤訊息代價高:生產環境關閉 display_errors,記錄 log_errors。
- 循環內禁用函數呼叫:
for($i=0;$i 每次呼叫 count()。
- 局部變數遞增最快:方法內
$a++ ≈ 函數內局部變數。
- 全域變數遞增慢 2 倍:需查找全域符號表。
- 物件屬性遞增慢 3 倍:
$this->prop++ 涉及屬性查找。
- 未初始化變數遞增慢 9-10 倍:觸發 E_NOTICE 並初始化。
- 宣告未使用的全域變數也會拖慢:PHP 需檢查是否存在。
方法與類設計(25-27)
- 方法數量不影響調用速度:類擴充 10 個方法無性能差異。
- 子類方法 > 父類方法:繼承鏈查找較短。
- 函數調用 ≈ 7-8 次局部遞增:方法調用 ≈ 15 次,儘量內聯關鍵路徑。
字串與輸出(28-29)
- 單引號 > 雙引號:單引號不解析變數,解析器更快。
- echo 多參數用逗號:
echo 'a', 'b' 僅 echo 支援。
架構與緩存(30-42)
- 靜態 HTML > PHP 腳本:Apache 解析靜態檔快 2-10 倍,盡量靜態化。
- 啟用 OPcache:PHP 5.5+ 內建,編譯緩存提升 25-100% 性能。
- 多層緩存策略:Memcached/Redis 緩存熱點資料,降低 DB 壓力;OPcache 緩存編譯碼。
- strlen() vs isset() 技巧:
if (!isset($str[5])) 比 if (strlen($str) < 5) 快(語言結構 vs 函數)。
- ++$i > $i++:前置遞增少一條 opcode(3 vs 4),不產生臨時變數。
- 非必要不 OOP:方法/物件調用有記憶體開銷,簡單邏輯用函數/陣列。
- 非必要不封裝類:陣列處理結構化資料往往更高效。
- 方法拆分適度:過度拆分增加調用開銷,重用才拆分。
- 善用內建函數:C 實現極快,勿重複造輪子。
- 極度耗時邏輯寫 C 擴展:或用 FFI(PHP 7.4+)呼叫共享庫。
- 定期 Profiling:Xdebug/Blackfire 找瓶頸,不要憑感覺優化。
- mod_gzip 壓縮輸出:同 mod_deflate,減少 80% 傳輸量。
總結:優化優先級
- 架構層:靜態化、緩存策略、資料庫索引/查詢優化、CDN。
- 配置層:OPcache、PHP-FPM 進程數、Web Server 壓縮/快取頭。
- 代碼層:避免 N+1 查詢、減少循環開銷、選對函數、善用內建。
- 微觀層:單雙引號、前後置遞增、isset 技巧(效果微小,最後考慮)。