Bug #29992 [Com]: foreach by reference corrupts the array

From: Date: Tue, 11 Feb 2014 03:35:00 +0000
Subject: Bug #29992 [Com]: foreach by reference corrupts the array
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-184252@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=29992&edit=1

 ID:                 29992
 Comment by:         xjis at msn dot com
 Reported by:        fletch at pobox dot com
 Summary:            foreach by reference corrupts the array
 Status:             Not a bug
 Type:               Bug
 Package:            Scripting Engine problem
 Operating System:   linux
 PHP Version:        5.0.1
 Block user comment: N
 Private report:     N

 New Comment:

well, i guess to be more exact, i should've said php doesn't have block scope support
whereas java/c++ does. 

now i see that even javascript has added block scoping starting 1.7 (need to use 'let'
instead of 'var' to declare block-scoped variables)


Previous Comments:
------------------------------------------------------------------------
[2014-02-11 00:27:18] xjis at msn dot com

guys... i read through this entire thread and now i totally get it.

this is just a weird "side-effect" of having a language being "function-level
scope" instead of "block-level scope" and with referencing support.

and as long as the language stays being 'function-level scope' that also has the
referencing support, this is the expected behavior; and there's no easy way around it. 

what ppl are expecting is exactly that of a block-level scope languages: having &v not
referencing anything after for-loop block ended. that's why ppl are keep referring to
C/C++/Java because these are all block-level scope languages; and why everyone wants for-loop to
"auto-unset" the &v after for-loop block ended; that would basically emulate/mimic the
behavior of block-level scope languages; but that is simply not the expected behavior for
function-level scope languages so you can't just make a special case only for for-loop blocks 
--why would you make a special exception just for for-loop; why not for the entire language? then
now, you are asking PHP language to completely change itself from being a function-level scope
language into a block-level scope language

btw, javascript is also a function-level scope language, but it doesn't have this particular
problem because it doesn't support referencing

------------------------------------------------------------------------
[2013-12-04 21:50:33] gray dot bowman at gmail dot com

Just wanted to chime in that 9 years on, this is still totally unexpected behavior.  Today, two
professional developers with years experience spent a couple hours trying to figure out why an array
that was demonstrably intact had its last element corrupted for apparently no reason once entering a
foreach.

------------------------------------------------------------------------
[2013-05-21 06:38:43] email at stevemann dot net

Agreed this is not a bug, it's expected behaviour. But it's dangerous as it can slip by
without being noticed. It almost certainly means there are 
thousands of sites which are exhibiting wrong behaviour because of this and no-one realises. Surely
the concept of scoping the 'as' variable to the 
foreach enclosure only can't be considered bad form. It would make so much more sense to
'opt-in' to retrieving the variable outside of the enclosure 
(by assigning to another persistent variable within the enclosure) rather than the current
'opt-out' system (using unset()) which, unless you happen 
to have read the warning is HIGHLY DANGEROUS.

------------------------------------------------------------------------
[2013-05-20 15:57:18] paul dot dillinger at gmail dot com

OK, I went over this some more.

<pre>
<?php
// Fresh array
$clean = array(1,2,3,4);

foreach($clean as &$item){
  // Nothing is modified in the array, but $item now exists
}

/*##############################################################################
 * $item persists outside of foreach and is now $clean[3] 
 * See the warning on http://php.net/manual/en/control-structures.foreach.php
 * print_r($item); // would return 4 you you uncommented this.
 * unset($item); // This would remove the pointer to $clean[3].  Expected.
 *############################################################################*/

echo "A:\n";
/*A*/       print_r($clean); // $clean is still unmodified

echo "B:\n";
            foreach($clean as $item){  
/*##############################################################################
 * Using AS $item SETS $item TO the current $item value (a.k.a. $clean[0], etc.)
 * Essentially foreach($clean as $item) is short hand for something like:
 * $x=0;while($x < count($clean)){$item=$clean[$x]; ### your code ###  $x++;}
 * The problem I had was that I did not expect foreach to be able to set on call
 *############################################################################*/

/*B*/           print_r($clean);
            }
?>
</pre>

So creating the variable is documented, and it isn't a bug.  
The ability to set the value could be made clearer though.

------------------------------------------------------------------------
[2013-05-20 09:51:33] richard at ejem dot cz

This IS a bug and SHOULD be finally fixed. It is weird, hard to debug and unexpected behavior which
took me many hours of life finding the problem. Almost every modern programming language has a
variable context, which guarrantees the foreach variable is not visible after exiting the loop.

Anyone is using it intentionally for "weird reason"? come on guys, almost every bug can be
used for some hacking or weird reasons, will it stop you from fixing other bugs? no!

Sorry for "mee-to" like post, but I do it for the good of next PHP programmer generations
who will also lose hours of their lives discovering this nonsense. Please fix it.

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


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

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


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


Thread (43 messages)

« previous php.bugs (#184252) next »