5

If I iterate through an array twice, once by reference and then by value, PHP will overwrite the last value in the array if I use the same variable name for each loop. This is best illustrated through an example:

$array = range(1,5);
foreach($array as &$element)
{
  $element *= 2;
}
print_r($array);
foreach($array as $element) { }
print_r($array);

Output:

Array ( [0] => 2 [1] => 4 [2] => 6 [3] => 8 [4] => 10 )

Array ( [0] => 2 [1] => 4 [2] => 6 [3] => 8 [4] => 8 )

Note that I am not looking for a fix, I am looking to understand why this is happening. Also note that it does not happen if the variable names in each loop are not each called $element, so I'm guessing it has to do with $element still being in scope and a reference after the end of the first loop.

3 Answers 3

7

After the first loop $element is still a reference to the last element/value of $array.
You can see that when you use var_dump() instead of print_r()

array(5) {
  [0]=>
  int(2)
...
  [4]=>
  &int(2)
}

Note that & in &int(2).
With the second loop you assign values to $element. And since it's still a reference the value in the array is changed, too. Try it with

foreach($array as $element)
{
  var_dump($array);
}

as the second loop and you'll see.
So it's more or less the same as

$array = range(1,5);
$element = &$array[4];
$element = $array[3];
// and $element = $array[4];
echo $array[4];

(only with loops and multiplication ...hey, I said "more or less" ;-))

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks! That makes complete sense.
5

Here's an explanation from the man himself:

$y = "some test";

foreach ($myarray as $y) {
    print "$y\n";
}

Here $y is a symbol table entry referencing a string containing "some test". On the first iteration you essentially do:

$y = $myarray[0];  // Not necessarily 0, just the 1st element

So now the storage associated with $y is overwritten by the value from $myarray. If $y is associated with some other storage through a reference, that storage will be changed.

Now let's say you do this:

$myarray = array("Test");
$a = "A string";
$y = &$a;

foreach ($myarray as $y) {
    print "$y\n";
}

Here $y is associated with the same storage as $a through a reference so when the first iteration does:

$y = $myarray[0];

The only place that "Test" string can go is into the storage associated with $y.

Comments

1

This is how you would fix this problem:

foreach($array as &$element)
{
    $element *= 2;
}
unset($element); #gets rid of the reference and cleans the var for re-use.

foreach($array as $element) { }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.