Bug #69725 [Nab]: foreach do not iterate all elements of an array in recursive function
| From: | dp dot maxime at gmail dot com | Date: | Fri, 29 May 2015 14:19:37 +0000 |
| Subject: | Bug #69725 [Nab]: foreach do not iterate all elements of an array in recursive function | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-193002@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=69725&edit=1
ID: 69725
User updated by: dp dot maxime at gmail dot com
Reported by: dp dot maxime at gmail dot com
Summary: foreach do not iterate all elements of an array in
recursive function
Status: Not a bug
Type: Bug
Package: Scripting Engine problem
Operating System: Ubuntu 15.04
PHP Version: 5.6.9
Block user comment: N
Private report: N
New Comment:
Sorry I don't think your assessment is correct.
Take a look on the level 0, i.e. first call of the recursive function, all works as expected,
meaning it does not match your explanation. The problem arises when you go deeper into recursion.
If I replace &$value by &$val in the second foreach the problem persists. Though I confirm
if you unset variables used in foreach constructs that gives what's expected. This is rather a
workaround.
Perhaps you missed that both $A and $B created from $X with assignment operator, not the assignment
by reference. Otherwise according to php manual
(http://php.net/manual/en/language.operators.assignment.php ):
"Note that the assignment copies the original variable to the new one (assignment by value), so
changes to one will not affect the other."
Regarding array assignment the manual states it explicitly
(http://php.net/manual/en/language.types.array.php):
"Array assignment always involves value copying."
The manual do not specify that this behaviour changes in recursive functions.
Thus changes into $A must not affect $B and $X.
Previous Comments:
------------------------------------------------------------------------
[2015-05-29 07:01:08] requinix@php.net
References. The explanation for why you get exactly those results is a bit complicated, I'll
explain if you need it, but the short version is that $value is a reference to the last element in
$A so when you set $value=$value+1 in the second foreach you'll also update $A which in turn
also affects $X and $B in the recursive calls.
unset($value) after the first loop to destroy the variable and the reference, then do it after the
second loop too so you learn to do that out of habit.
------------------------------------------------------------------------
[2015-05-29 06:36:15] dp dot maxime at gmail dot com
Description:
------------
foreach construct do not iterate all elements of an array in recursive functions.
I am using PHP 5.6.9 from ppa:ondrej/php5-5.6 on Ubuntu 15.04.
The version 5.6.4 from the standard Ubuntu 15.04 distribution is also affected.
Test script:
---------------
<?php
function R(&$X, $level) {
print "$level X: " . json_encode($X) . "\n";
$A = $X;
foreach($A as &$value) {
$value = $value - 1;
}
print "$level A: " . json_encode($A) . "\n";
$B = $X;
foreach($B as &$value) {
$value = $value + 1;
}
print "$level B: " . json_encode($B) . "\n";
if ($level < 3) {
R($B, $level + 1);
}
}
$X = array(1, 2, 3);
R($X, 0);
Expected result:
----------------
0 X: [1,2,3]
0 A: [0,1,2]
0 B: [2,3,4]
1 X: [2,3,4]
1 A: [1,2,3]
1 B: [3,4,5]
2 X: [3,4,5]
2 A: [2,3,4]
2 B: [4,5,6]
3 X: [4,5,6]
3 A: [3,4,5]
3 B: [5,6,7]
Actual result:
--------------
0 X: [1,2,3]
0 A: [0,1,2]
0 B: [2,3,4]
1 X: [2,3,4]
1 A: [1,2,3]
1 B: [3,4,4]
2 X: [3,4,4]
2 A: [2,3,3]
2 B: [4,5,4]
3 X: [4,5,4]
3 A: [3,4,3]
3 B: [5,6,4]
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=69725&edit=1