Bug #69725 [Nab]: foreach do not iterate all elements of an array in recursive function

From: 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

« previous php.bugs (#193002) next »