陣列遍歷是 PHP 開發中最高頻的操作之一。常見的三種寫法——foreach、while + list/each、for——在語法風格與執行效能上有何差異?本文透過實測與原理分析,給出明確建議。
$urls = ['aaa', 'bbb', 'ccc', 'ddd'];
foreach ($urls as $url) {
echo "URL: $url
";
}
// 需要鍵值時
foreach ($urls as $key => $val) { ... }
$urls = ['aaa', 'bbb', 'ccc', 'ddd'];
while (list($key, $val) = each($urls)) {
echo "URL: $val
";
}
// 注意:each() 在 PHP 7.2 棄用,PHP 8.0 移除
$urls = ['aaa', 'bbb', 'ccc', 'ddd'];
for ($i = 0; $i < count($urls); $i++) {
echo "URL: {$urls[$i]}
";
}
$arr = [];
for ($i = 0; $i < 50000; $i++) {
$arr[] = $i * mt_rand(1000, 9999);
}
function getMicrotime(): float {
[$usec, $sec] = explode(' ', microtime());
return (float)$usec + (float)$sec;
}
// 1. for
$start = getMicrotime();
for ($i = 0; $i < count($arr); $i++) { $v = $arr[$i]; }
echo 'for: ' . round(getMicrotime() - $start, 7) . "s\n";
// 2. while + each
$start = getMicrotime();
while (list($k, $v) = each($arr)) { }
echo 'while: ' . round(getMicrotime() - $start, 7) . "s\n";
// 3. foreach
$start = getMicrotime();
foreach ($arr as $k => $v) { }
echo 'foreach: ' . round(getMicrotime() - $start, 7) . "s\n";
for: 0.0228429s while: 0.0544658s foreach: 0.0085628s
| 維度 | foreach | while+each | for |
|---|---|---|---|
| 實作層級 | C 核心內建(Zend VM 專用 opcode) | 用戶空間函式呼叫 + 內部指標移動 | 通用迴圈結構 + 索引存取 |
| 記憶體操作 | 遍歷陣列副本(COW 機制,極低開銷) | 直接操作原陣列內部指標 | 索引查找 + 邊界檢查 |
| 函式呼叫 | 無額外呼叫 | 每次迴圈呼叫 each()、list() | 每次迴圈評估 count()(若未優化) |
| PHP 版本支援 | 全版本,持續優化 | PHP 7.2 棄用,8.0 移除 | 全版本 |
| 適用場景 | 絕大多數遍歷需求 | 不建議新專案使用 | 需索引控制、逆序、步進等特殊邏輯 |
count($arr) 提前儲存:$len = count($arr); for ($i=0; $i<$len; $i++),避免每次迴圈呼叫函式。foreach ($arr as &$v) { $v *= 2; } unset($v); 直接修改原陣列值。掌握遍歷方法的效能特性,能在處理大量資料時寫出更高效的 PHP 程式碼。