Edit report at http://bugs.php.net/bug.php?id=29992&edit=1

 ID:                 29992
 Updated by:         [email protected]
 Reported by:        fletch at pobox dot com
 Summary:            foreach by reference corrupts the array
 Status:             Bogus
 Type:               Bug
 Package:            Scripting Engine problem
 Operating System:   linux
 PHP Version:        5.0.1
 Block user comment: N
 Private report:     N

 New Comment:

I explained this with some pictures in my blog:
http://schlueters.de/blog/archives/141-References-and-foreach.html



And no, unsetting after the loop is no option as it is inconsistent with
other loops and there are valid reasons for keeping it after the loop.
Something along the lines of



foreach ($array as &$item) {

    if ($item == "foo") {

        break;

    }

}



$item = "bar";


Previous Comments:
------------------------------------------------------------------------
[2010-11-27 10:28:58] tarama at hotmail dot com

I highly agree with looris. I had to patch each use of hundreds of
foreach loops in my code due to this weird behaviour. The unset() tips
at the end of each loop does the job, but from my point of view it's
really not logical. It caused really hard to find bugs in my code and I
prefer to not imagine how many PHP scritps are running on the web with
the same "bug" silently breaking things.

------------------------------------------------------------------------
[2010-05-24 19:20:22] looris at gmail dot com

This *IS* a bug, since no one would EVER expect this kind of behaviour.

And no one "might use this for some weird reason", believe me.



"foreach" means "do stuff FOR EACH element of an array".

It does not mean, to any sane person, "do stuff for each element of an
array except the last one, and twice for the one before the last one".



Your stubbornness in stating this is intentional is quite frightening.

------------------------------------------------------------------------
[2006-08-07 14:18:11] [email protected]

Although there's a user note in the manual, still this problem is not
described in the documentation itself.



Anyway, I believe the behaviour of foreach in this case is extremely
dangerous. Imagine there's such a "referential" loop in a library which
is included by some other scripts and it operates on $_SESSION or some
other important array. Now any foreach in the other scripts might
corrupt the base array without even knowing it - just because the name
of the "value" variable is the same.



The main purpose of foreach itself is (as the name implies) to do
something "for each" element of the array, i.e. to provide an easier way
to traverse an array than the other loop constructs and not to touch
other variables or references that are still pointing somewhere, unless
it's done implicitly in the body of the loop.



IMHO, foreach has to clear the variables used for key-value pairs, i.e.
to unset the reference before proceeding, just like it resets the array
pointer. Otherwise we have to put a big red note in the manual to always
unset variables after using the referential syntax or to use
$long_descriptive_names_for_references, which is a little unreasonable
in the current context.

------------------------------------------------------------------------
[2004-10-08 08:54:14] [email protected]

Thank you for taking the time to write to us, but this is not
a bug. Please double-check the documentation available at
http://www.php.net/manual/ and the instructions on how to report
a bug at http://bugs.php.net/how-to-report.php

Right, thanks for that analysis. No bug here. (And no, we can't unset it
by default, as people might use this for some weird reason).

------------------------------------------------------------------------
[2004-10-07 21:12:18] gardan at gmx dot de

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?)

------------------------------------------------------------------------


The remainder of the comments for this report are too long. To view
the rest of the comments, please view the bug report online at

    http://bugs.php.net/bug.php?id=29992


-- 
Edit this bug report at http://bugs.php.net/bug.php?id=29992&edit=1

Reply via email to