PHP DISCUSSION

PHP foreach by reference leaves my array with a duplicated last element: what is happening?

Started by alexpuga PHP foreach referencedangling referenceunset after looparray_mapcopy on write
4 replies 248 views 5 participants
Latest activity · 30 Sep 2026

PHP foreach by reference leaves my array with a duplicated last element: what is happening?

alexpuga PHP Forum
#1

I scale an array of readings in place with foreach ($values as &$v) { $v = $v * 2; }. Later in the same function a second loop, foreach ($values as $v) { echo $v; }, prints the last value wrong: for [1, 2, 3] I expect 2, 4, 6 and get 2, 4, 4. After that the array itself really contains 2, 4, 4.

The second loop only reads. How can it change the array, and how should I write the first loop?

Community replies 4

Re: PHP foreach by reference leaves my array with a duplicated last element: what is happening?

#2

After the first loop finishes, $v is still a reference to the last element, $values[2]. PHP has no block scope, so the variable and its reference binding survive the loop. The second loop then assigns each element to $v in turn, and every one of those assignments writes through the reference into $values[2].

Step by step, starting from 2, 4, 6: the first iteration copies 2 into the last slot (2, 4, 2), the second copies 4 (2, 4, 4), and the third reads the last slot, which now holds 4. Hence 2, 4, 4.

Re: PHP foreach by reference leaves my array with a duplicated last element: what is happening?

#3

The fix is one line: unset($v); immediately after the by-reference loop. That removes the reference binding without touching the array element. Make it a habit to write the unset at the same moment you write the &.

The bug does not need a second foreach, either; any later assignment to a variable called $v in the same scope, even fifty lines down, silently overwrites the last element.

Re: PHP foreach by reference leaves my array with a duplicated last element: what is happening?

#4

Or avoid the reference. foreach ($values as $k => $v) { $values[$k] = $v * 2; } modifies by key and leaves nothing dangling. $values = array_map(fn($v) => $v * 2, $values); builds a new array and is the clearest for a pure transformation (arrow functions need PHP 7.4 or later).

People sometimes reach for & believing it saves memory. It does not: PHP arrays are copy-on-write, so a by-value foreach does not duplicate the array unless something modifies it during the loop.

Re: PHP foreach by reference leaves my array with a duplicated last element: what is happening?

#5

References linger in one more way worth knowing. An array element that is bound to a reference stays a reference inside the array, and that property is carried along when the array is copied. After your first loop without unset, $copy = $values; followed by $v = 99; changes the last element of both arrays, because both share the referenced slot.

A quick way to convince yourself: run the two loops with and without the unset and call print_r($values) after each step. With the unset in place the array stays 2, 4, 6 throughout.

TEP COMMUNITY