This is driving me crazy. Recursive functions seem to work differently in 5.4.4 and 5.1.6 (hosting server of a client over which I have no control). I can't really explain it except by example:
<?php
$simpsons[0] = array("name"=>"Abe","parent"=>-1);
$simpsons[1] = array("name"=>"Homer","parent"=>0); // Homer's parent is Abe
$simpsons[2] = array("name"=>"Bart","parent"=>1); // Bart's parent is Homer
$simpsons[3] = array("name"=>"Lisa","parent"=>1); // Lisa's parent is Homer
$simpsons[4] = array("name"=>"Maggie","parent"=>1); // Maggie's parent is Homer
function get_children($parent) {
global $simpsons;
foreach ($simpsons as $index=>$onesimpson) {
if ($onesimpson["parent"]==$parent) {
echo "$onesimpson[name] is a child of ".$simpsons[$parent]["name"].".<br />\n";
get_children($index);
}
}
}
get_children(0);
?>
On PHP 5.4.4 the output is
Homer is a child of Abe.
Bart is a child of Homer.
Lisa is a child of Homer.
Maggie is a child of Homer.
while on PHP 5.1.6 the output is
Homer is a child of Abe.
Bart is a child of Homer.
I'm not good with terminology so I can't explain what's happening (it's like in 5.1.6 the called function changes the parameter of the calling function even when the called function finishes), but I've tested this in PHP sandbox online on these two versions and the problem is identical - it's not specific to my setup or the hosting server setup.
I'm not sure what changed to make that start working in 5.2, but an array only has one internal pointer (that is what is used by foreach), so when you use a global array like that the result you see in versions up to 5.2 make a lot of sense. You start a foreach loop, the internal pointer advances, then you recursively call get_children, start another foreach loop and the internal pointer resets and then iterates through the array.
When you return to the callee, the internal pointer will be at the end of the array already and the foreach loop will complete. To quote the manual:
As foreach relies on the internal array pointer changing it within the loop may lead to unexpected behavior.
Using foreach within a foreach on the same array is an example of that.
Edit I found a couple of relevant bug reports that were marked fixed in version 5.2.1:
It turns out that foreach works on a clone of the array, so nesting foreach loops is perfectly valid and this was indeed a bug, where array references were not cloned in foreach loops) up until version 5.2.1.
I have tweaked your code a little bit. Apparently when you pass the $simpsons
array reference as a parameter to your recursive function, it works in all versions.
$simpsons = array();
$simpsons[0] = array("name"=>"Abe","parent"=>-1);
$simpsons[1] = array("name"=>"Homer","parent"=>0); // Homer's parent is Abe
$simpsons[2] = array("name"=>"Bart","parent"=>1); // Bart's parent is Homer
$simpsons[3] = array("name"=>"Lisa","parent"=>1); // Lisa's parent is Homer
$simpsons[4] = array("name"=>"Maggie","parent"=>1); // Maggie's parent is Homer
function get_children($simpsons, $parent) {
foreach ($simpsons as $index=>$onesimpson) {
if ($onesimpson["parent"]==$parent) {
echo "$onesimpson[name] is a child of ".$simpsons[$parent]["name"].".<br />\n";
get_children($simpsons, $index);
}
}
}
get_children($simpsons, 0);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With