php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #31118 Two consecutive foreach loops produce different results
Submitted: 2004-12-16 12:26 UTC Modified: 2005-01-07 07:24 UTC
Votes:3
Avg. Score:3.0 ± 1.6
Reproduced:0 of 2 (0.0%)
From: dennis at inmarket dot lviv dot ua Assigned: andi (profile)
Status: Wont fix Package: Scripting Engine problem
PHP Version: 5.0.2 OS: Win
Private report: No CVE-ID: None
Have you experienced this issue?
Rate the importance of this bug to you:

 [2004-12-16 12:26 UTC] dennis at inmarket dot lviv dot ua
Description:
------------
If you foreach an array with a reference (foreach $a as $x=>&$y), modifying $y, and then without it (foreach $a as $x=>$y), on the second time it will return incorrect results. 
The sample code has two functions - each iterates over array with a reference to value and modifies it and then they foreach that array - first function without a reference, and the second - with a reference. The first function fails to iterate to the end of array. However, the print_r shows the array is ok.

Reproduce code:
---------------
function test1() {
  $a = array('key1'=>'value1', 'key2'=>'value2', 'key3'=>'value3');
  foreach($a as $k=>&$v) {
    $v .= '0';
  }
  print_r($a);
  foreach($a as $k=>$v) {
    echo $k .'=' . $v . "\r\n";
  }
}

function test2() {
  $a = array('key1'=>'value1', 'key2'=>'value2', 'key3'=>'value3');
  foreach($a as $k=>&$v) {
    $v .= '0';
  }
  print_r($a);
  foreach($a as $k=>&$v) {
    echo $k .'=' . $v . "\r\n";
  }
}
test1();
test2();


Expected result:
----------------
Array
(
    [key1] => value10
    [key2] => value20
    [key3] => value30
)
key1=value10
key2=value20           <- all values properly changed
key3=value30     
Array
(
    [key1] => value10
    [key2] => value20
    [key3] => value30
)
key1=value10
key2=value20           <- all values properly changed
key3=value30

Actual result:
--------------
Array
(
    [key1] => value10
    [key2] => value20
    [key3] => value30
)
key1=value10
key2=value20
key3=value20           <- SHOULD BE '30'
Array
(
    [key1] => value10
    [key2] => value20
    [key3] => value30
)
key1=value10
key2=value20
key3=value30

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2004-12-16 12:43 UTC] tony2001@php.net
Please do not submit the same bug more than once. An existing
bug report already describes this very problem. Even if you feel
that your issue is somewhat different, the resolution is likely
to be the same. 

Thank you for your interest in PHP.

See #29992.
 [2004-12-16 16:05 UTC] dennis at inmarket dot lviv dot ua
No, it is NOT related no those bugs: here is a test case that proves that with no array modification two consecutive foreach loops give different results

$a = array('key1'=>'value1', 'key2'=>'value2', 'key3'=>'value3');
foreach($a as $k=>&$v) {
  echo $k . '=' . $v . "\r\n";
}
foreach($a as $k=>$v) {
  echo $k . '=' . $v . "\r\n";
}

This produces this:

key1=value1
key2=value2
key3=value3
key1=value1
key2=value2
key3=value2 <- must be 3
 [2004-12-16 16:08 UTC] dennis at inmamrket dot lviv dot ua
Sorry for opening another ticket but this bug took me 2 weeks to shuffle the code and I got really nervous about it. This is abnormal behaviuor, and the bug you forwarded me to is different - there is array modification inside the loop.
 [2004-12-23 23:48 UTC] andi@php.net
I looked into this problem. It's actually not a bug but just "weird" behavior as a result of PHP blocks not having scope.
Basically the first foreach() statement leaves the value variable ($v) as a reference. When the second loop runs, it "assigns" the current array's position to $v. Because $v was a reference it'll actually overwrite the previously pointed to value.

Now we can't go and unset($v) at the end of the foreach() statement as I bet there are many applications out there that take advantage of the last value staying in the $v variable after the foreach() finishes.

The only thing I have in mind is possible emitting an E_STRICT during the foreach() loop if the loop value variable is a reference. However, just from looking at make test this might potentially break many scripts which are using E_STRICT and/or confuse their authors. Not sure how to weight that, and as we haven't had many complaints about this behavior I'm not sure it's worth it.

Taking this to internals@ but most likely, it'll remain this way.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri Apr 26 22:01:29 2024 UTC