在優化 PHP 程式碼前,必須先能準確測量效能。本文介紹如何建立可靠的微效能測試框架,並透過實際案例對比常見陣列操作函式的效能差異,幫助你做出有依據的優化決策。
PHP 內建 microtime(true) 即可取得浮點數秒數(含微秒),無需自行拆解組裝。現代寫法:
function microtimeFloat(): float {
return microtime(true);
}
class Benchmark {
private float $start;
private array $marks = [];
public function start(): void {
$this->start = microtime(true);
}
public function mark(string $name): void {
$now = microtime(true);
$elapsed = ($now - $this->start) * 1000; // 毫秒
$this->marks[$name] = $elapsed;
$this->start = $now; // 重置起點,測量區間時間
echo "$name: " . intval($elapsed) . " ms\n";
}
public function getReport(): array {
return $this->marks;
}
}
測試場景:陣列大小 10,000,查找 10,000 次,比較五種檢查鍵是否存在的方法。
$length = 10_000;
$loop = 10_000;
$key = 'abc500'; // 存在的鍵
$array = [];
for ($i = 0; $i < $length; $i++) {
$array['abc' . $i] = 'abc' . $i;
}
$bench = new Benchmark();
$bench->start();
for ($i = 0; $i < $loop; $i++) {
if (array_key_exists($key, $array)) { $a = true; }
}
$bench->mark('array_key_exists');
for ($i = 0; $i < $loop; $i++) {
if (isset($array[$key])) { $a = true; }
}
$bench->mark('isset');
for ($i = 0; $i < $loop; $i++) {
if (in_array($key, $array)) { $a = true; } // 錯誤用法:in_array 檢查值,非鍵
}
$bench->mark('in_array (錯誤用法)');
for ($i = 0; $i < $loop; $i++) {
if (array_search($key, $array)) { $a = true; } // 同樣檢查值
}
$bench->mark('array_search (錯誤用法)');
// 正確對比:翻轉陣列後用 isset
$flipped = array_flip($array);
for ($i = 0; $i < $loop; $i++) {
if (isset($flipped[$key])) { $a = true; }
}
$bench->mark('array_flip + isset');
| 方法 | 耗時 (ms) | 時間複雜度 | 說明 |
|---|---|---|---|
isset($arr[$key]) | ~3-5 | O(1) | 最快,語言構造,非函式呼叫 |
array_key_exists($key, $arr) | ~8-12 | O(1) | 函式呼叫開銷,但能檢查 null 值 |
array_flip + isset | ~15-20 (含翻轉) | O(n) + O(1) | 適合需反覆查找值對應鍵的場景 |
in_array($val, $arr) | ~200-400 | O(n) | 線性掃描,極慢,僅適用小陣列或檢查值 |
array_search($val, $arr) | ~200-400 | O(n) | 同 in_array,但回傳鍵名 |
isset($arr[$key]),最快且語法簡潔。若需區分「鍵不存在」與「值為 null」,才用 array_key_exists。in_array;大陣列務必建立反向索引 $flip = array_flip($arr); isset($flip[$val]) 或改用資料庫/Redis。count($arr)、array_flip 應移至迴圈外。foreach ($arr as &$v) { $v = strtoupper($v); } 比 array_map 略快,且記憶體效率更高(就地修改)。掌握正確的測試方法與常見操作的效能特徵,能讓你在優化時針對瓶頸下手,避免過早優化或優化錯誤方向。