第一輪foreach改完價格,資料明明是11、21、31;接著只是再走訪一次,最後一項卻變成21。若前一輪寫了&$price,先查迴圈結束後有沒有unset($price)。引用不會隨著右大括號自動解除,後面再用同一個變數,就可能改到陣列尾項。
第二輪看似只讀,為何改了尾項
把下面程式存成PHP檔執行。第一輪透過引用替每個值加1,第二輪沒有寫任何更新陣列的程式,卻仍會改變結果。
<?php
$prices = [10, 20, 30];
foreach ($prices as &$price) {
$price += 1;
}
echo json_encode($prices), PHP_EOL;
// [11,21,31]
foreach ($prices as $price) {
// 這裡沒有主動修改陣列
}
echo json_encode($prices), PHP_EOL;
// [11,21,21]
第一輪結束時,$price仍連著$prices最後一項。第二輪雖然沒有&,每次把元素值指派給$price,仍會透過殘留引用寫進尾項;輪到最後一項時,它已被前面的21覆蓋。問題不是json_encode,也不是陣列排序。
引用用完,立即解除連結
在引用迴圈結束後加上unset($price),再開始下一輪。用完整程式重新執行,避免前一次實驗留下的引用干擾結果。
<?php
$prices = [10, 20, 30];
foreach ($prices as &$price) {
$price += 1;
}
unset($price);
foreach ($prices as $price) {
// 後續一般走訪
}
echo json_encode($prices), PHP_EOL;
// [11,21,31]
這裡unset的是引用變數$price,解除它與陣列元素的連結,不是刪除$prices的最後一項。不要誤寫成unset($prices[2]),那會移除元素。第一輪已完成的加1結果,也不會因為解除引用而還原。
不需要引用,就明確按key回寫
若只是更新每一項,可以改用key指定位置,把引用的生命週期問題拿掉。
<?php
$prices = [10, 20, 30];
foreach ($prices as $key => $price) {
$prices[$key] = $price + 1;
}
foreach ($prices as $price) {
// 後續一般走訪
}
echo json_encode($prices), PHP_EOL;
// [11,21,31]
這個例子只處理整數陣列,沒有在迴圈內新增或刪除元素。若你的程式還會改變陣列結構、走訪物件或處理巢狀引用,需另外檢查那些行為,不能只憑這個輸出推斷全部情境。
回到原程式,從引用建立處往後查
搜尋foreach中的&,找出引用變數,確認它在哪個位置解除。如果提早break離開,也要讓流程走到必要的清理;不要只改下一輪的變數名稱,卻把仍可覆寫尾項的引用留在同一作用域裡。
先用小陣列比較「引用迴圈剛結束」及「下一次使用變數後」兩個時間點。把非預期變更縮到最短範圍,再改實際資料處理程式,會比一路追查輸出格式更直接。

評論0