Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I'm really getting crazy with this since two days now. I'd greatly appreciate if someone could give me a hint. I definitely can't understand why this PHP code:

$arr [] = [ "name" => "Chapter 1" ];
$arr [] = [ "name" => "Chapter 2" ];

foreach ( $arr as &$item )
    echo $item['name']."<br>";

echo "============<br>";

foreach ( $arr as $item )
    echo $item['name']."<br>";

gives this output:

Chapter 1
Chapter 2
============
Chapter 1
Chapter 1      (I would expect 'Chapter 2' here)

It looks like the first loop modifies the array, even though there is no assignment in the loop. Strangely enough, everything works as expected, when I remove the ampersand.

The thing I don't understand is, why is the array getting modified at all, even though I don't do anything with the reference variable '&$item' variable (except echoing it).

I also tried reset() between the loops. But it didn't change anything, and according to the manual it shouldn't be necessary anyway in such a case (at lease from my understanding) because the loops start after each other and are not nested somehow.

Thanks a lot!

Bernd

share|improve this question
    
remove "&" from &$item in first foreach :-) –  Eugen 2 days ago
3  
Add unset($item) immediately after the first loop. –  raina77ow 2 days ago
1  
possible duplicate of PHP Pass by reference in foreach –  raina77ow 2 days ago
    
Yes that would be the easiest way :-). But the snippet above is just a piece of code that I've stripped down to show the essential problem. The reason I can't remove it is that in the real code indeed I need to modify the array from within the loop. Of course a 'for' - loop also works well, but I don't like building workarounds just because I don't understand the initial problem. –  Bernd 2 days ago

3 Answers 3

up vote 1 down vote accepted

After any loop completes, the variables used in it still exist. For instance:

for( $i=0; $i<10; $i++) {
    // do something
}
echo $i; // 10

The same applies to references. After the loop is done, $item is still a reference to the last item in the array. Thus when you write foreach($arr as $item) a second time, you're now using that reference to the last element and repeatedly re-assigning it, which results in the last element of the array being assigned (by reference) the same thing as the second-to-last item.

To fix, be sure to clean up:

unset($item); // delete the reference

In theory you should clean up after any loop, but in pretty much all other cases it won't matter. It's just that in this case, it does!

share|improve this answer
    
Yes that works. Thanks a lot for your ubelievable fast, good and detailed explanation! Simply great !!! –  Bernd 2 days ago

You can read more here http://pl.php.net/manual/en/control-structures.foreach.php

"In order to be able to directly modify array elements within the loop precede $value with &. In that case the value will be assigned by reference."

Example:

$arr = array(1, 2, 3, 4);
foreach ($arr as &$value) {
    $value = $value * 2;
}
// $arr is now array(2, 4, 6, 8)
unset($value); // break the reference with the last element
share|improve this answer

The array is not technically getting modified in your code sample, but a reference point is being attached to one of your array values. If you modify your example to read:

$arr [] = [ "name" => "Chapter 1" ];
$arr [] = [ "name" => "Chapter 2" ];
echo '<pre>';
var_dump($arr);

foreach ( $arr as &$item )
    echo $item['name']."<br>";

echo "============<br>";

var_dump($arr);

foreach ( $arr as $item )
    echo $item['name']."<br>";

echo $item['name'];

You can examine the var dump output and see the reference pointer in the second var dump:

array(2) {
    [0]=>
    array(1) {
        ["name"]=>
        string(9) "Chapter 1"
    }
    [1]=>
    array(1) {
        ["name"]=>
        string(9) "Chapter 2"
    }
}
Chapter 1
Chapter 2
============
array(2) {
    [0]=>
    array(1) {
        ["name"]=>
        string(9) "Chapter 1"
    }
    [1]=>
    &array(1) {
        ["name"]=>
        string(9) "Chapter 2"
    }
}
Chapter 1
Chapter 1

My theory is it has something to do with how PHP is handling reference pointers internally. As others have suggested, just run unset($item) in between the loops and you can mitigate the issue.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.