當數據量龐大且動態變化時,手動 echo $arr[0] 顯然不可行。PHP 提供了強大的 foreach 結構,專為數組/對象遍歷設計。本文系統梳理其語法變體、內部指針行為、值/引用模式差異及常見誤區。
<?php
$urls = [
'新浪' => 'www.sina.com',
'騰訊' => 'www.qq.com',
'百度' => 'www.baidu.com',
];
foreach ($urls as $site) {
echo "<a href='https://$site'>$site</a><br>";
}
// 輸出:鍵名被忽略,$site 依序為三個域名
?>
foreach ($urls as $name => $link) {
echo "<a href='https://$link'>$name</a><br>";
}
// $name = '新浪', $link = 'www.sina.com' ... 語義清晰
$n = 0;
foreach ($urls as $name => $link) {
echo ++$n . "、<a href='https://$link'>$name</a><br>";
}
// 輸出:1、新浪 2、騰訊 3、百度
foreach 開始前會自動調用 reset(),指針指向首元素。無需手動 reset($arr)。
$arr = [1, 2, 3];
foreach ($arr as $v) {
$v *= 10; // 修改副本
}
print_r($arr); // [1, 2, 3] 原陣列不變
$arr = [1, 2, 3];
foreach ($arr as &$v) { // 注意 & 符號
$v *= 10;
}
print_r($arr); // [10, 20, 30] 原陣列被修改
unset($v); // 關鍵:斷開引用,防止後續誤用
$arr = ['a' => 1, 'b' => 2];
foreach ($arr as $k => &$v) { // 僅值引用,鍵名不可引用
// $k 只是字符串副本
}
| 陷阱 | 後果 | 正確做法 |
|---|---|---|
遍歷中 unset($arr[$k]) | 跳過下一元素/死循環 | 先收集待刪鍵名,遍歷後批量刪除 |
引用模式未 unset($v) | $v 保持引用,污染後續邏輯 | 循環結束後必須 unset($v) |
用 @ 抑制錯誤 | foreach 不支持錯誤抑制運算符 | 預先 is_array() 校驗 |
| 遍歷多維數組層級不定 | 需遞歸/迭代器 | 使用 RecursiveArrayIterator |
// 關聯數組:foreach 唯一優雅選擇
foreach ($assoc as $k => $v) { ... }
// 純數值索引、需控制步長:for 更靈活
for ($i = 0; $i < count($arr); $i += 2) { ... }
// 需在遍歷中修改結構:while + each/next
while (list($k) = each($arr)) {
if (cond) unset($arr[$k]); // 安全
}
function huge_data() {
for ($i = 0; $i < 1_000_000; $i++) {
yield $i => $i * 2; // 惰性生成,內存常數級
}
}
foreach (huge_data() as $k => $v) {
// 處理百萬級數據,內存僅佔 KB 級
}
foreach 是 PHP 遍歷數組的首選:語法清晰、自動管理指針、支持鍵值解構。掌握值模式與引用模式的邊界、遍歷中修改結構的禁忌、引用後必須 unset,能避開 90% 的坑。對於超大數據集,善用生成器(yield)實現流式處理,將內存佔用降至最低。