萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 程式設計 >  >> 網路程式設計 >> PHP 程式設計

PHP 高效能寫法 40 條:從語法優化到架構層面的效能調校

前言

PHP 效能優化涵蓋語法層面、函式選擇、記憶體管理、快取策略等多個維度。本文整理 40 條實戰驗證的高效能寫法,附上原理說明與效能比較。

語法與基本優化 (1-10)

1. 單引號優於雙引號

<?php
// ✅ 單引號:不解析變數,較快
echo 'Hello ' . $name;

// ❌ 雙引號:需解析變數
echo "Hello $name";

// ✅ echo 多參數(無連接開銷)
echo 'Hello ', $name, '!';

2. 靜態方法提升 4 倍速度

<?php
class Math {
    // ✅ 靜態方法:無需實例化,呼叫快 ~4 倍
    public static function add(int $a, int $b): int {
        return $a + $b;
    }
    
    // ❌ 實例方法:需建立物件
    public function addInstance(int $a, int $b): int {
        return $a + $b;
    }
}

Math::add(1, 2); // 快
// (new Math())->addInstance(1, 2); // 慢

3. 陣列鍵名加引號

<?php
// ✅ $row['id'] 比 $row[id] 快 7 倍
// $row[id] 會先嘗試尋找常數 id,再當作字串
$id = $row['id'];

4. echo 優於 print,多參數優於連接

<?php
// ✅ 快
echo $str1, $str2, $str3;

// ❌ 慢:字串連接建立暫時變數
echo $str1 . $str2 . $str3;

// ❌ print 回傳值,有微小開銷
print $str;

5. foreach 優於 for,預計算最大值

<?php
// ✅ foreach 專為陣列優化
foreach ($arr as $item) { ... }

// ✅ for 循環預計算 count
$count = count($arr);
for ($i = 0; $i < $count; $i++) { ... }

// ❌ 每次迴圈都呼叫 count()
for ($i = 0; $i < count($arr); $i++) { ... }

6. 釋放大型變數記憶體

<?php
$largeData = fetchHugeDataset();
// 處理完後
unset($largeData);
// 或設為 null
$largeData = null;
// 觸發 GC(PHP 7+ 通常自動處理)
gc_collect_cycles();

7. 避免魔術方法開銷

<?php
// ⚠️ 魔術方法有額外開銷,非必要勿用
class Heavy {
    public function __get($name) { ... }      // 讀取不存在屬性
    public function __set($name, $value) { ... } // 寫入不存在屬性
    public function __call($name, $args) { ... } // 呼叫不存在方法
    public function __autoload() { ... }        // 已棄用
}

// ✅ 明確定義屬性與方法,避免觸發魔術方法

8. require_once 成本高,改用 autoload

<?php
// ❌ 每次都檢查已載入清單
require_once 'file.php';

// ✅ Composer PSR-4 自動載入,僅載入需要的類別
require_once __DIR__ . '/vendor/autoload.php';

9. 使用絕對路徑 include

<?php
// ✅ 避免搜尋 include_path
include __DIR__ . '/config.php';
include '/var/www/shared/lib.php';

// ❌ 相對路徑需搜尋 include_path
include 'config.php';

10. 取得請求開始時間用 $_SERVER['REQUEST_TIME']

<?php
// ✅ 精確、無函式呼叫開銷
$startTime = $_SERVER['REQUEST_TIME'];
// 或高精度
$startTimeFloat = $_SERVER['REQUEST_TIME_FLOAT'];

// ❌ time() 有函式呼叫開銷
$startTime = time();

函式選擇優化 (11-20)

11. 字串替換:strtr > str_replace > preg_replace

<?php
// ✅ 最快:strtr 單字元對應
$str = strtr($str, ['&' => '&', '<' => '<', '>' => '>']);

// ✅ 次快:str_replace 陣列批次替換
$str = str_replace(['&', '<', '>'], ['&', '<', '>'], $str);

// ❌ 最慢:正則表達式
$str = preg_replace('/[&<>]/', fn($m) => ['&'=>'&','<'=>'<','>'=>'>'][$m[0]], $str);

12. 簡單替換拆分為單字元多次呼叫

<?php
// 當替換對象較少時,多次單一替換可能比陣列替換快
$str = str_replace('a', 'b', $str);
$str = str_replace('c', 'd', $str);
// vs
$str = str_replace(['a','c'], ['b','d'], $str);

13. switch 優於多重 if-else

<?php
// ✅ switch 使用跳躍表,O(1) 查找
switch ($action) {
    case 'create': ... break;
    case 'read': ... break;
    case 'update': ... break;
    case 'delete': ... break;
}

// ❌ 多重 if-else 線性查找 O(n)
if ($action === 'create') ...
elseif ($action === 'read') ...

14. 避免 @ 抑制錯誤

<?php
// ❌ 極慢:@ 會修改錯誤報告層級、產生例外處理開銷
$file = @file_get_contents($path);

// ✅ 正確錯誤處理
if (file_exists($path)) {
    $file = file_get_contents($path);
} else {
    // 處理不存在
}

// ✅ 或使用 try-catch (PHP 8+ 許多函式拋出例外)
try {
    $file = file_get_contents($path);
} catch (Throwable $e) {
    // 處理
}

15. 啟用 Apache mod_deflate / mod_gzip

# .htaccess 或 httpd.conf

    AddOutputFilterByType DEFLATE text/html text/css application/json
    AddOutputFilterByType DEFLATE application/javascript text/xml application/xml

16. 資料庫連線用完即關,避免長連線

<?php
// ✅ 短連線:請求結束自動關閉
$pdo = new PDO($dsn, $user, $pass);
// 執行查詢...
// 腳本結束自動斷開

// ⚠️ 長連線需小心管理
$pdo = new PDO($dsn, $user, $pass, [PDO::ATTR_PERSISTENT => true]);

17. 錯誤訊息產生有開銷

<?php
// 避免在迴圈中產生錯誤
for ($i = 0; $i < 10000; $i++) {
    // ❌ 觸發 Notice 會大幅降速
    echo $undefinedVar;
    
    // ✅ 正確檢查
    echo $definedVar ?? '';
}

變數操作微優化 (18-25)

18-25. 遞增操作速度層級

<?php
// 基準:局部變數遞增
$local = 0;
$local++; // 最快 (基準)

// 全域變數:慢 2 倍
$GLOBALS['g'] = 0;
$GLOBALS['g']++;

// 物件屬性:慢 3 倍
$obj->prop = 0;
$obj->prop++;

// 未定義局部變數:慢 9-10 倍
$undefined++; // 先初始化為 0 再遞增

// 定義但未使用的局部變數:同遞增局部變數開銷
function test() {
    $unused = 1; // 定義未用
    $used = 1;
    $used++;
}

前置遞增優於後置遞增

<?php
$i = 0;
++$i; // ✅ 3 opcodes,直接遞增
$i++; // ❌ 4 opcodes,建立暫存變數

架構與設計層面 (26-40)

26. 靜態 HTML 優於 PHP 腳本 (2-10 倍)

<?php
// ✅ 靜態內容用 .html 或快取輸出
// ❌ 簡單頁面也用 PHP 處理

27. 啟用 OPcache (PHP 5.5+ 內建)

; php.ini
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
opcache.revalidate_freq=60 ; 生產環境 60s 或 0 (需重啟)
opcache.validate_timestamps=1
opcache.save_comments=1

28. 使用快取:Redis / Memcached / APCu

<?php
// Redis 範例
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);

$cacheKey = 'user:123:profile';
$data = $redis->get($cacheKey);
if ($data === false) {
    $data = fetchUserProfileFromDb(123);
    $redis->setex($cacheKey, 3600, json_encode($data));
}
$user = json_decode($data, true);

29. strlen() vs isset() 技巧

<?php
$str = 'hello';

// ❌ strlen() 函式呼叫開銷
if (strlen($str) < 5) { ... }

// ✅ isset() 語言結構,無函式呼叫
// 檢查第 5 個字元 (索引 4) 是否存在
if (!isset($str[4])) { ... } // 長度 < 5

30. 避免在迴圈中呼叫函式

<?php
// ❌ 每次迴圈呼叫 count()
for ($i = 0; $i < count($arr); $i++) { ... }

// ✅ 預先計算
$count = count($arr);
for ($i = 0; $i < $count; $i++) { ... }

31. 類別方法數量不影響呼叫速度

測試證實:類別定義 10 或 100 個方法,呼叫特定方法速度無差異。

32. 子類別方法比父類別快

繼承鏈越短、方法越接近呼叫處,解析越快。

33. 函式呼叫 ≈ 7-8 次局部遞增;方法呼叫 ≈ 15 次

減少不必要的函式/方法封裝層級。

34. 單引號字串不解析變數

重申第 1 點,確保不需變數插值時用單引號。

35. 不盲目面向物件

<?php
// ❌ 過度封裝簡單邏輯
class UserHelper {
    public static function getName($user) { return $user['name']; }
}

// ✅ 簡單情況直接存取
$name = $user['name'];

36. 陣列勝過物件儲存純資料

<?php
// ✅ 純資料傳輸物件 (DTO) 用陣列或 readonly class (PHP 8.1+)
readonly class UserDto {
    public function __construct(
        public int $id,
        public string $name,
        public string $email
    ) {}
}

// 大量資料陣列記憶體效率優於物件陣列

37. 避免過度拆分方法

YAGNI 原則:只在真正需要重用時才抽出方法。

38. 需要時再重構

過早優化是萬惡之源。先寫正確、可讀、可測試的程式碼。

39. 善用內建函式

<?php
// ✅ 內建函式通常用 C 實作,極快
$max = max($arr);
$sum = array_sum($arr);
$filtered = array_filter($arr, fn($x) => $x > 0);
$unique = array_unique($arr);

// ❌ 手寫迴圈重複造輪子

40. 考慮 JIT (PHP 8.0+)

; php.ini
opcache.jit_buffer_size=100M
opcache.jit=tracing

; 適用於 CPU 密集型計算(數學、圖像處理)
; I/O 密集型 (Web 請求) 效果有限

效能優化優先級矩陣

優先級項目影響難度
🔴 關鍵OPcache 啟用⚡⚡⚡⚡⚡低
🔴 關鍵資料庫索引/查詢優化⚡⚡⚡⚡⚡中
🔴 關鍵快取策略 (Redis/資料庫查詢快取)⚡⚡⚡⚡中
🟠 高Composer 自動載入優化 (--classmap-authoritative)⚡⚡⚡低
🟠 高靜態資源 CDN + 壓縮⚡⚡⚡低
🟡 中語法微優化 (單引號、foreach、isset 技巧)⚡⚡低
🟢 低遞增/遞減運算子選擇⚡低
copyright © 萬盛學電腦網 all rights reserved