PHP递归函数在不同版本中的工作方式不同?

时间:2013-08-21 16:20:05

标签: php

这让我发疯了。递归函数似乎在5.4.4和5.1.6(托管我无法控制的客户端服务器)中的工作方式不同。除了例子,我无法解释它:

<?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);
?>

在PHP 5.4.4上输出

Homer is a child of Abe.
Bart is a child of Homer.
Lisa is a child of Homer.
Maggie is a child of Homer.

在PHP 5.1.6上输出

Homer is a child of Abe.
Bart is a child of Homer.

我对术语不太好所以我无法解释发生了什么(就像在5.1.6中被调用函数改变了调用函数的参数,即使被调用的函数完成),但我已经在关于这两个版本的PHP沙箱在线并且问题是相同的 - 它不是特定于我的设置或托管服务器设置。

2 个答案:

答案 0 :(得分:8)

我不确定是什么改变使得开始在5.2中工作,但是一个数组只有一个内部指针(这是foreach使用的),所以当你使用像这样的全局数组时你看到的结果版本高达5.2很有意义。你启动一个foreach循环,内部指针前进,然后递归调用get_children,启动另一个foreach循环,内部指针重置,然后遍历数组。

当你返回被调用者时,内部指针已经在数组的末尾,foreach循环将完成。 To quote the manual

  

由于foreach依赖于内部数组指针,因此在循环内更改它可能会导致意外行为。

在同一阵列的foreach中使用foreach就是一个例子。

编辑我发现了一些在5.2.1版中标记为已修复的相关错误报告:

事实证明,foreach在数组的克隆上运行,因此嵌套foreach循环是完全有效的,这确实是一个错误,其中数组引用未在foreach循环中克隆)直到版本5.2.1。

答案 1 :(得分:3)

我稍微调整了你的代码。显然,当您将$simpsons数组引用作为参数传递给递归函数时,它适用于所有版本。

$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);