I had to spend a few hours to figure out why a[3] is changing on each iteration. This is the explanation at which I arrived.
There are two types of variables in PHP: normal variables and reference variables. If we assign a reference of a variable to another variable, the variable becomes a reference variable.
for example in
$a = array('zero', 'one', 'two', 'three');
if we do
$v = &$a[0]
the 0th element ($a[0]
) becomes a reference variable. $v
points towards that variable; therefore, if we make any change to $v
, it will be reflected in $a[0]
and vice versa.
now if we do
$v = &$a[1]
$a[1]
will become a reference variable and $a[0]
will become a normal variable (Since no one else is pointing to $a[0]
it is converted to a normal variable. PHP is smart enough to make it a normal variable when no one else is pointing towards it)
This is what happens in the first loop
foreach ($a as &$v) {
}
After the last iteration $a[3]
is a reference variable.
Since $v
is pointing to $a[3]
any change to $v
results in a change to $a[3]
in the second loop,
foreach ($a as $v) {
echo $v.'-'.$a[3].PHP_EOL;
}
in each iteration as $v
changes, $a[3]
changes. (because $v
still points to $a[3]
). This is the reason why $a[3]
changes on each iteration.
In the iteration before the last iteration, $v
is assigned the value 'two'. Since $v
points to $a[3]
, $a[3]
now gets the value 'two'. Keep this in mind.
In the last iteration, $v
(which points to $a[3]
) now has the value of 'two', because $a[3]
was set to two in the previous iteration. two
is printed. This explains why 'two' is repeated when $v is printed in the last iteration.