2013-08-21 11 views
5

これは私を夢中にしています。再帰関数は、5.4.4と5.1.6(私が制御できないクライアントのホスティングサーバ)で異なって動作するようです。私は実際の例による場合を除いて、それを説明することはできません:PHPでPHPの再帰関数は、異なるバージョンで動作が異なりますか?

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

を出力

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

である5.4.4 PHPの中には、出力が

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

である5.1.6 I私は何も起きていないので、何が起きているのか説明できません(呼び出された関数が呼び出された関数が終了しても、呼び出された関数のパラメータが変更されます)。しかし、これをPHPサンドボックスでオンラインでテストしました。これら2つのバージョン問題は同じです。セットアップやホスティングサーバーの設定に固有の問題ではありません。

+1

問題が確認されました:http://3v4l.org/n1mVc –

+1

私は最初の赤い旗である配列として$ simpsonsを決して定義しません。 '$ simpsons = array();'を '<?php'の直後に追加すると何かに影響しますか? –

+0

@ AndrewG.Johnson:悲しいことですが、それは有効なPHPコードです。 '$ simpsons [0] = array(" name "=>" Abe "、" parent "=> - 1);'は単に配列を自動作成します。 Docs:http://www.php.net/manual/en/language.types.array.php#language.types.array.syntax.modifying非常に落胆しますが、有効です。 –

答えて

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); 
+0

これはテスト済みです。 http://3v4l.org/aSr6C :-D –

+0

これは明らかに答えですが、なぜ 'global $ simpsons; 'がエラーを引き起こしたのだろうと思います。たぶん過去に修正されたエラーだったかもしれません。 –

+1

ありがとう、私は元の問題(オンライン店舗で商品の子カテゴリを収集)にそれを適用することができましたし、それは大丈夫、おそらく、グローバルなvarsを左右に宣言するのではなく、最初にこれを行う正しい方法です – L84

8

私はそれが5.2で作業を開始するように変更かわからないんだけど、配列が一つだけ内部ポインタを(つまり、foreachので使用されるものである)があるので、あなたがそのようなグローバル配列を使用する場合5.2までのバージョンでは、多くの意味があることがわかります。 foreachループを開始し、内部ポインタを前進させ、次に再帰的にget_childrenを呼び出し、別のforeachループを開始し、内部ポインタをリセットして配列を反復処理します。

呼び出し先に戻ると、内部ポインタが配列の最後にあり、foreachループが完了します。 To quote the manual

foreachは、ループ内で内部配列ポインタを変更すると、予想外の動作につながる可能性があります。

foreach内のforeachを同じ配列に使用することはその例です。

編集私はバージョン5.2.1で修正されたマークされた関連するバグレポートのカップルが見つかりました:それは、foreachのは、上で動作することが判明し

を配列のクローンを作成するので、foreachループを入れ子にすることは完全に有効です。これはバージョン5.2.1までの配列参照がforeachループでクローン化されなかったバグでした。

+0

私が問題を説明できないのも不思議ではありません! :-) – L84

+0

私は 'global $ simpsons;'が同じ配列を参照するようにしていて、同じポインタを参照させていると思っていました。しかし、私はforeachがポインタをリセットするのを見たので、それは問題ではないと思った。それはそうだった。 :-) –

関連する問題