ID: 29992
Comment by: gardan at gmx dot de
Reported By: fletch at pobox dot com
Status: Open
Bug Type: Zend Engine 2 problem
Operating System: linux
PHP Version: 5.0.1
New Comment:
There is no corruption. It is easy to explain this behaviour. Take the
following:
$arr = array(1 => array(1, 2), 2 => array(1, 2), 3 => array(1, 2));
foreach($arr as &$value) { }
foreach(array(1,2,3,4,5) as $key => $value) { }
echo $test[3];
After the first foreach() loop what you have in $value is a reference
to the last element in $arr (here: to array(1,2)).
Now, when the next foreach loop assigns a value to $value, it assigns
this value to where $value points, that is: to the last position of
$arr. Now in the second foreach() the last item of $arr becomes first
1, then 2, etc and in the end, what you get as output by this program,
is:
5
Not the expected:
Array
Now this is indeed very confusing if you don't know what's going on.
Solution:
unset $v before a new foreach() loop (maybe this could be done by php
by default?)
Previous Comments:
------------------------------------------------------------------------
[2004-10-04 16:49:05] yaroukh at email dot cz
I'm [Apache/2.0.48 (Win32) PHP/5.0.2]
------------------------------------------------------------------------
[2004-10-04 16:37:43] yaroukh at email dot cz
I believe the problem I'm gonna describe here has the same roots as the
one fletch has described ...
Try this:
<? class ArrayWrapper {
protected $slots;
public function __construct($slots = Array())
{
$this->slots =& $slots;
}
public function & getSlot($idx)
{
if(IsSet($this->slots[$idx]))
return $this->slots[$idx];
return null;
}
public function getLength()
{
return Count($this->slots);
}
}
// fill the array and create object {
$slots = Array(
'zero',
'one',
'two',
'three',
'four'
);
$aw = new ArrayWrapper($slots);
// }
// output A
var_dump($aw);
// iteration 1
for($idx = 0; $idx < $aw->getLength(); $idx++)
$aw->getSlot($idx);
// output B; everything is OK
var_dump($aw);
// iteration 2
for($idx = 0; $idx < $aw->getLength(); $idx++)
if($aw->getSlot($idx))
{
}
// output C; elements have been changed to references
var_dump($aw);
?>
As you can see in output "C" the second iteration altered elements of
the array - the elements have been turned into references. (Or did I
get the ampersand-sign wrong?) The problem is that I loose control over
the REAL objects and the elements get changed unreasonably later in the
script.
I kind of understand what's the diference between getSlot() and
getSlot() used within an if-loop (I guess the scope created by if-loop
makes the difference), but I'm not sure this difference entitles PHP to
alter my array.
Can anyone explain this to me? Is it a bug or a regular behaviour?
------------------------------------------------------------------------
[2004-09-06 08:04:28] fletch at pobox dot com
changed the summary
------------------------------------------------------------------------
[2004-09-06 05:54:50] fletch at pobox dot com
Description:
------------
foreach with a reference seems to corrupt the last element in an array
Reproduce code:
---------------
<?php
$array = array(1,2,3);
foreach( $array as &$item ) { }
print_r( $array );
foreach( $array as $item ) { }
print_r( $array );
?>
Expected result:
----------------
Array
(
[0] => 1
[1] => 2
[2] => 3
)
Array
(
[0] => 1
[1] => 2
[2] => 3
)
Actual result:
--------------
Array
(
[0] => 1
[1] => 2
[2] => 3
)
Array
(
[0] => 1
[1] => 2
[2] => 2
)
------------------------------------------------------------------------
--
Edit this bug report at http://bugs.php.net/?id=29992&edit=1