PHP foreach跑完資料卻變了:引用變數用完記得unset

第一輪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離開,也要讓流程走到必要的清理;不要只改下一輪的變數名稱,卻把仍可覆寫尾項的引用留在同一作用域裡。

先用小陣列比較「引用迴圈剛結束」及「下一次使用變數後」兩個時間點。把非預期變更縮到最短範圍,再改實際資料處理程式,會比一路追查輸出格式更直接。

參考資料

原文鏈接:https://wntheme.com/php-foreach-reference-unset-loop-variable/,轉載請註明出處。
0

評論0

顯示驗證碼
沒有帳號?註冊  忘記密碼?