萬盛學電腦網

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

PHP foreach 循環遍歷陣列完整指南:語法、參考傳遞陷阱與最佳實踐

foreach 基本語法

<?php
$arr = ['one', 'two', 'three'];

// 僅取值
foreach ($arr as $value) {
    echo "Value: $value
"; } // 取鍵與值 foreach ($arr as $key => $value) { echo "Key: $key, Value: $value
"; }

參考傳遞修改原陣列(核心進階用法)

$arr = ['a', 'b', 'c'];

// ✅ 正確:參考傳遞修改值
foreach ($arr as &$value) {
    $value = strtoupper($value);
}
unset($value);  // ★★★ 關鍵:解除參考綁定
print_r($arr);  // ['A', 'B', 'C']

// ❌ 錯誤:忘記 unset 導致後續迴圈異常
foreach ($arr as &$value) { $value = strtoupper($value); }
// 此時 $value 仍參考 $arr[2]

foreach ($arr as $value) {  // 以值模式迴圈
    // $value 複製值給 $arr[2]!導致最後一元素被覆蓋
    echo $value;  // 輸出:A B B(最後變成倒數第二個值)
}
unset($value);  // 補救

參考陷阱深度解析

PHP 陣列迴圈時會複製陣列(Copy-on-Write),但參考傳遞 `&$value` 會強制建立對原陣列元素的參考。迴圈結束後,`$value` 仍參考最後一個元素。若後續以值模式 `foreach ($arr as $value)` 迴圈,PHP 會將 `$value` 的值複製給每個元素,**包括最後一個**,導致最後一元素被倒數第二個值覆蓋。

安全寫法三選一

寫法一:參考修改 + unset(效能最好)

foreach ($arr as &$v) {
    $v = process($v);
}
unset($v);  // 必須

foreach ($arr as $v) { /* 唯讀 */ }

寫法二:鍵值寫入(無參考風險,語意清晰)

foreach ($arr as $k => $v) {
    $arr[$k] = process($v);
}

foreach ($arr as $v) { /* 唯讀 */ }

寫法三:array_map/array_walk 函數式風格(現代推薦)

// 返回新陣列,不修改原陣列
$new_arr = array_map('process', $arr);

// 修改原陣列(內部用參考)
array_walk($arr, function(&$v) { $v = process($v); });

foreach 進階技巧

遍歷時安全刪除元素

$arr = ['a', 'b', 'c', 'd'];

foreach ($arr as $key => $value) {
    if ($value === 'b') {
        unset($arr[$key]);  // 安全:不影響迴圈指標
    }
}
// 結果:['a', 'c', 'd'](鍵名保留 0,2,3)

遍歷時新增元素(不會被迭代到)

$arr = ['a', 'b'];
foreach ($arr as $key => $value) {
    if ($value === 'a') {
        $arr[] = 'new';  // 不會在本次迴圈被處理
    }
}
// 迴圈只跑 2 次

多維陣列遍歷

$users = [
    ['name' => 'Alice', 'tags' => ['php', 'js']],
    ['name' => 'Bob', 'tags' => ['python']],
];

foreach ($users as $user) {
    echo $user['name'] . ': ';
    foreach ($user['tags'] as $tag) {
        echo $tag . ' ';
    }
    echo "
"; }

解構賦值(PHP 7.1+)

$people = [
    ['Alice', 25, 'Engineer'],
    ['Bob', 30, 'Designer'],
];

foreach ($people as [$name, $age, $job]) {
    echo "$name ($age) - $job
"; } // 關聯陣列解構 foreach ($people as ['name' => $name, 'age' => $age]) { echo "$name is $age years old
"; }

效能提示

  • `foreach` 比 `for`/`while` 快(內部優化,無需手動計數)
  • 大陣列唯讀遍歷:`foreach ($arr as $v)` 無額外開銷
  • 需修改值:`foreach ($arr as &$v)` + `unset($v)` 比鍵值寫入略快
  • 避免在迴圈中呼叫 `count()`:`for ($i=0; $i
copyright © 萬盛學電腦網 all rights reserved