php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #68215 Behavior of foreach has changed
Submitted: 2014-10-13 03:13 UTC Modified: 2014-10-14 04:24 UTC
From: pegasus at vaultwiki dot org Assigned:
Status: Closed Package: Scripting Engine problem
PHP Version: master-Git-2014-10-13 (Git) OS: Centos 6 64-bit
Private report: No CVE-ID: None
 [2014-10-13 03:13 UTC] pegasus at vaultwiki dot org
Description:
------------
Historically, foreach ($arr AS $val) has acted on a copy of $arr, in order to prevent issues if $arr entries are modified after the loop has already begun iterating. If the current value was desired, historically for or while loops were used instead.

However, in Master, it appears that $arr always refers to the current value of $arr. This is in contradiction to the historical behavior. If entries are added inside the loop, foreach will keep going for the new entries. If existing entries are otherwise modified, the $val corresponds to the updated entry rather than the $val when the loop began.




Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2014-10-13 11:25 UTC] derick@php.net
-Status: Open +Status: Feedback
 [2014-10-13 11:25 UTC] derick@php.net
Can you please provide a reproducible case as a short PHP script?
 [2014-10-13 18:41 UTC] pegasus at vaultwiki dot org
It seems I may not have properly described the issue at first. I noticed this happening to code someone else had written, and it was part of a massive library. It took many hours of trial and error to rewrite this library as a "short" PHP script, such that it still had the same discrepancy between PHP 5.6.0 and Master.

Test script:
####
$arr = array(
	'a' => array(
		'a' => 'apple',
		'b' => 'banana',
		'c' => 'cranberry',
		'd' => 'mango',
		'e' => 'pineapple'
	),
	'b' => array(
		'a' => 'apple',
		'b' => 'banana',
		'c' => 'cranberry',
		'd' => 'mango',
		'e' => 'pineapple'
	),
	'c' => 'cranberry',
	'd' => 'mango',
	'e' => 'pineapple'
);

function test(&$child, $entry)
{
	$i = 1;

	foreach ($child AS $key => $fruit)
	{
		if (!is_numeric($key))
		{
			$child[$i] = $fruit;
			unset($child[$key]);
			$i++;
		}
	}
}

$i = 1;

foreach ($arr AS $key => $fruit)
{
	$arr[$i] = $fruit;

	if (is_array($fruit))
	{
		test($arr[$i], $fruit);
	}

	unset($arr[$key]);
	$i++;
}

var_dump($arr);
####
Expect: In 5.6, this re-keys a,b,c,d,e at all array levels as 1,2,3,4,5 respectively.
Actual: In Master, this re-keys correctly on the outer-most level. On the second level, only a,b,c,d is re-keyed.

Notes: This has something to do with the reference in the definition for function test. If we break the reference within the function, then Master replicates the expected 5.6 behavior:
####
function test(&$child, $entry)
{
	$i = 1;
	$tmp = $child;

	foreach ($tmp AS $key => $fruit)
	{
		if (!is_numeric($key))
		{
			$child[$i] = $fruit;
			unset($child[$key]);
			$i++;
		}
	}
}
####
 [2014-10-14 02:42 UTC] pegasus at vaultwiki dot org
-Status: Feedback +Status: Open
 [2014-10-14 02:42 UTC] pegasus at vaultwiki dot org
Test script provided above.
 [2014-10-14 04:24 UTC] rasmus@php.net
-Status: Open +Status: Verified
 [2014-10-14 04:24 UTC] rasmus@php.net
Yes, looks like a problem in master:

http://3v4l.org/XrVYT
 [2014-10-15 13:03 UTC] dmitry@php.net
Automatic comment on behalf of dmitry@zend.com
Revision: http://git.php.net/?p=php-src.git;a=commit;h=ed18d67c5e69e4b5713e940568e5b3d0a7392a8d
Log: Fixed bug #68215 (Behavior of foreach has changed)
 [2014-10-15 13:03 UTC] dmitry@php.net
-Status: Verified +Status: Closed
 [2014-10-16 11:58 UTC] ab@php.net
Automatic comment on behalf of dmitry@zend.com
Revision: http://git.php.net/?p=php-src.git;a=commit;h=ed18d67c5e69e4b5713e940568e5b3d0a7392a8d
Log: Fixed bug #68215 (Behavior of foreach has changed)
 [2016-07-20 11:40 UTC] davey@php.net
Automatic comment on behalf of dmitry@zend.com
Revision: http://git.php.net/?p=php-src.git;a=commit;h=ed18d67c5e69e4b5713e940568e5b3d0a7392a8d
Log: Fixed bug #68215 (Behavior of foreach has changed)
 
PHP Copyright © 2001-2021 The PHP Group
All rights reserved.
Last updated: Fri Jan 22 17:01:23 2021 UTC