PHP 效能優化不是玄學,而是可量化、可驗證的工程實踐。本文彙總 53 條實戰優化規則,涵蓋 語法微優化、資料結構選擇、資料庫交互、緩存策略、基礎設施調優 五大維度,附效能測試方法論。
| # | 規則 | 原理/備註 |
|---|---|---|
| 1 | 字串用單引號,雙引號僅用於變量插值 | 單引號不解析變量,少一次掃描;echo 多參數 echo $a,$b 比連接 echo $a.$b 快 |
| 2 | 靜態方法優於實例方法 | 無需實例化、無 $this 解析,約 20-30% 更快 |
| 3 | 陣列鍵名加引號 $arr['key'] | 無引號會先查常數再轉字串,慢 3-7 倍 |
| 4 | echo 快於 print,多參數優於連接 | print 有返回值,多一步 opcode |
| 5 | 循環前計算最大值,避免重複 count() | for($i=0,$len=count($arr);$i<$len;$i++) 或改用 foreach |
| 6 | 及時 unset() 大變量釋放記憶體 | 特別是大陣列、物件、資源句柄 |
| 7 | 避免魔術方法 __get/__set/__call | 觸發攔截器開銷大,熱路徑禁用 |
| 8 | require_once 開銷大,生產環境用類映射/OPcache | Composer ClassMap + OPcache 可消除檢查開銷 |
| 9 | include 使用絕對路徑 | 避免遍歷 include_path,減少 stat 系統調用 |
| 10 | 用 $_SERVER['REQUEST_TIME_FLOAT'] 代替 time() | 無函數調用開銷,精度更高 |
| 11 | 字串替換:strtr > str_replace > preg_replace | strtr 單次掃描多模式,C 層優化最佳 |
| 12 | 大量替換時,單字元循環優於陣列參數 | 避免內部哈希表構建開銷 |
| 13 | switch 優於多層 if-else | 編譯為 jump table,O(1) 分發 |
| 14 | 禁用 @ 抑制錯誤 | 極其昂貴,會修改錯誤處理器上下文 |
| 15 | 啟用 mod_deflate/mod_gzip 壓縮輸出 | 傳輸量降低 70-80%,CPU 換頻寬極划算 |
| # | 規則 | 關鍵點 |
|---|---|---|
| 16 | 請求結束關閉 DB 連接,避免長連接洩漏 | PDO: $pdo=null;連接池由基礎設施管理 |
| 17 | 錯誤訊息開銷大,生產關閉顯示、記錄日誌 | Xdebug 生產環境必須關閉 |
| 18 | 局部變量遞增最快,全域變量慢 2x,物件屬性慢 3x | 作用域查找鏈長度差異 |
| 19 | 未定義局部變量遞增慢 9-10x (會觸發符號表查找) | 始終初始化變量 |
| 20 | 僅定義未使用的局部變量也會拖慢速度 | 編譯期符號表膨脹 |
| 21 | 方法調用開銷與類方法數無關 | Zend VM 緩存方法查找 |
| 22 | 子類方法執行快於父類同名方法 | 繼承鏈查找深度差異 |
| 23 | 空函數調用 ≈ 7-8 次局部遞增;方法調用 ≈ 15 次 | 函數調用幀開銷固定 |
| 24 | PHP 解析慢於靜態 HTML 2-10 倍 | 靜態化策略:Nginx fastcgi_cache、Varnish、預渲染 |
| 25 | 啟用 OPcache (PHP 5.5+ 內建) | 編譯緩存提升 25-100%,opcache.enable=1、opcache.jit=1255 (PHP 8+) |
| # | 策略 | 實施要點 |
|---|---|---|
| 26 | 多層緩存:OPcache → Redis/Memcached → CDN → 瀏覽器 | 各層職責分離,失效策略分級 |
| 27 | 數據熱點用 Redis (String/Hash/Set/SortedSet) | 序列化用 igbinary/msgpack,避免 PHP serialize |
| 28 | 緩存穿透/擊穿/雪崩三大問題必有對策 | 空值緩存、互斥鎖重建、隨機過期時間 |
| 29 | strlen() vs isset($str[n]) 檢查長度 | isset 是語言結構,無函數調用開銷 |
| 30 | ++$i 快於 $i++ (少一個臨時變量 opcode) | PHP 特有,C/Java 不適用 |
| 31 | 非必要不用 OOP,陣列/結構體輕量得多 | 物件創建/GC 開銷大,熱路徑用陣列 |
| 32 | 方法拆分適度,避免過度封裝 | 調用開銷 vs 復用收益權衡 |
| 33 | 優先使用內建函數 (C 實現) | array_map vs 手寫循環,前者通常更快 |
| 34 | 極致效能寫 C 擴展 / FFI / Rust 共享庫 | 計算密集型:圖像處理、加密、壓縮、解析 |
| 35 | 持續 Profiling:Xdebug/Blackfire/Tideways | 找出真正瓶頸,避免過早優化 |
| # | 項目 | 配置建議 |
|---|---|---|
| 36 | PHP-FPM 池配置 | pm=dynamic、pm.max_children 按記憶體計算、pm.max_requests=500 防洩漏 |
| 37 | OPcache 生產配置 | opcache.memory_consumption=256、opcache.max_accelerated_files=20000、opcache.validate_timestamps=0 (部署時清理) |
| 38 | JIT 編譯 (PHP 8.1+) | opcache.jit=1255 (tracing+avx),計算密集型提升 1.5-3x |
| 39 | Nginx fastcgi_cache | 全頁緩存、fastcgi_cache_key 含用戶標識、fastcgi_cache_valid 200 30m |
| 40 | 靜態資源 CDN + 長期緩存 | Cache-Control: public, max-age=31536000, immutable、檔名含 hash |
| 41 | 資料庫連接池 | PgBouncer (PostgreSQL)、ProxySQL (MySQL)、避免 PHP 端長連接 |
| 42 | 慢查詢日誌 + 索引優化 | long_query_time=0.5、EXPLAIN 分析、覆蓋索引 |
| 43 | file_get_contents 替代 fopen/fread 系列 | 單次系統調用、內存映射優化、注意 URL wrapper 版本差異 |
| 44 | 減少檔案 I/O,改用共享記憶體/Redis | Session、快取、鎖、計數器全進內存 |
| 45 | SQL 優化:少 SELECT *、避免 N+1、批次 INSERT/UPDATE | INSERT ... VALUES (),(),()、ON DUPLICATE KEY UPDATE |
| # | 技巧 | 說明 |
|---|---|---|
| 46 | 盡用內建函數,別重造輪子 | array_column, array_key_first, str_contains (PHP 8+) |
| 47 | 循環內勿聲明大變量/物件 | 移至循環外復用,減少 GC 壓力 |
| 48 | 多維陣列避免嵌套循環賦值 | 用 array_map/array_walk/生成器 |
| 49 | 能用字串函數別用正則 | strpos/substr/explode 比 PCRE 快數量級 |
| 50 | foreach 優於 for/while | 內部指針迭代,無索引運算 |
| 51 | 單引號字串、i+=1 微優化 | 習慣即規範,累積效應可觀 |
| 52 | 全域變量用完 unset() | 減少符號表掃描、防止意外引用 |
| 53 | 定期 composer update、PHP 版本升級 | 新版本帶來 JIT、內建函數優化、安全修復 |
# 1. 微基準測試 (語法層面)
php -r '$t=microtime(true); for($i=0;$i<1e6;$i++) $a=$i+1; echo microtime(true)-$t;'
# 2. 壓力測試 (端到端)
wrk -t4 -c100 -d30s --latency https://localhost/api/users
# 關鍵指標:QPS、P99 延遲、錯誤率、CPU/記憶體
# 3. Profiling 定位熱點
# Xdebug: xdebug.mode=profile → kcachegrind/qcachegrind 分析
# Blackfire: 黑盒持續分析、對比報告
# Tideways: 低開銷生產級采樣
# 4. 效能預算
# 目標:P99 < 200ms、QPS > 1000、記憶體 < 128MB/請求
# CI 門禁:每次 PR 跑基準測試,退步 > 5% 禁止合並