2013-08-21 15 views
5

Das macht mich verrückt. Rekursive Funktionen scheinen in 5.4.4 und 5.1.6 (Hosting-Server eines Clients, über den ich keine Kontrolle habe) anders zu funktionieren. Ich kann es nicht wirklich erklären, mit Ausnahme von Beispiel:PHP rekursive Funktionen funktionieren in verschiedenen Versionen anders?

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

auf PHP 5.4.4 die Ausgabe

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

während auf PHP ist 5.1.6 die Ausgabe

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

I bin nicht gut mit Terminologie, so kann ich nicht erklären, was passiert (es ist wie in 5.1.6 die aufgerufene Funktion ändert den Parameter der aufrufenden Funktion, selbst wenn die aufgerufene Funktion beendet ist), aber ich habe dies in PHP Sandbox online getestet diese zwei versi ons und das Problem ist identisch - es ist nicht spezifisch für meine Einrichtung oder das Hosting-Server-Setup.

+1

Problem bestätigt: http://3v4l.org/n1mVc –

+1

Sie definieren nie $ Simpsons als ein Array, das die erste rote Flagge für mich ist. Wenn Sie '$ simpsons = array();' unmittelbar nach '

+0

@ AndrewG.Johnson: So traurig wie es mich macht, ist das gültige PHP-Code. '$ simpsons [0] = array (" name "=>" Abe "," parent "=> - 1);' erstellt einfach automatisch ein Array. Docs: http://www.php.net/manual/en/language.types.array.php#language.types.array.syntax.modify Es ist sehr davon abgeraten, aber es ist gültig. –

Antwort

3

Ich habe Ihren Code ein wenig optimiert. Offenbar, wenn Sie die Array-Referenz $simpsons als Parameter an Ihre rekursive Funktion übergeben, funktioniert es in allen Versionen.

$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

Getestet, das funktioniert! http://3v4l.org/aSr6C :-D –

+0

Dies ist eindeutig die Antwort, aber ich frage mich, warum 'global $ simpsons;' Fehler verursacht hat. Vielleicht war es ein Fehler, der in der Vergangenheit behoben wurde. –

+1

Danke, ich habe es geschafft, es auf das ursprüngliche Problem anzuwenden (Sammeln von Kind Kategorien von Produkten in einem Online-Shop) und es funktioniert gut, wahrscheinlich der richtige Weg, dies zu tun, anstatt globale Vars links und rechts zu erklären – L84

8

Ich bin nicht sicher, was geändert, dass in 5.2 Arbeit zu machen starten, aber ein Array hat nur einen internen Zeiger (das ist, was von foreach verwendet wird), so dass, wenn Sie verwenden, um ein globales Array wie das die Ergebnisse, die Sie in Versionen bis 5.2 sehen, machen sehr viel Sinn. Sie starten eine foreach-Schleife, der interne Zeiger rückt vor, dann rufen Sie rekursiv get_children auf, starten eine weitere foreach-Schleife und der interne Zeiger wird zurückgesetzt und iteriert dann durch das Array.

Wenn Sie zum aufgerufenen Objekt zurückkehren, befindet sich der interne Zeiger bereits am Ende des Arrays und die foreach-Schleife wird abgeschlossen. To quote the manual:

Da foreach auf den internen Array-Zeiger angewiesen ist, kann das Ändern innerhalb der Schleife zu unerwartetem Verhalten führen.

Die Verwendung von foreach innerhalb einer foreach auf dem gleichen Array ist ein Beispiel dafür.

bearbeiten fand ich ein paar relevante Fehlerberichte, die 5.2.1 in Version behoben markiert wurden:

Es stellt sich heraus, dass foreach auf ein Werk Klon des Arrays, so dass die Verschachtelung von foreach Loops absolut gültig ist und dies ein Fehler war, bei dem Array Referenzen nicht in foreach Loops geklont wurden) bis Version 5.2.1.

+0

Kein Wunder, dass ich das Problem nicht erklären konnte! :-) – L84

+0

Ich dachte, dass "global $ simpsons;" es auf das gleiche Array und damit auf den gleichen Zeiger verweist. Aber ich sah, dass 'foreach' den Zeiger zurücksetzte, also nahm ich an, dass das nicht das Problem war. Scheint es war. :-) –

Verwandte Themen