2013-08-21 18 views
5

To doprowadza mnie do szału. Funkcje rekurencyjne wydają się działać inaczej w 5.4.4 i 5.1.6 (serwer hostingowy klienta, nad którym nie mam kontroli). I naprawdę nie można wytłumaczyć tylko przez przykład:Funkcje rekursywne PHP działają inaczej w różnych wersjach?

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

o PHP 5.4.4 wyjście jest

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

podczas PHP 5.1.6 wyjście jest

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

I "Nie jestem dobry z terminologią, więc nie mogę wyjaśnić, co się dzieje (to tak, jak w 5.1.6 wywołana funkcja zmienia parametr funkcji wywołującej, nawet gdy wywoływana funkcja się kończy), ale testowałem to w piaskownicy PHP online na te dwie wersje ons i problem są identyczne - nie jest to specyficzne dla mojej konfiguracji lub konfiguracji serwera hostingowego.

+1

Problem potwierdzony: http://3v4l.org/n1mVc –

+1

Nigdy nie definiujesz $ simpsons jako tablicy, która jest dla mnie pierwszą czerwoną flagą. Jeśli dodasz '$ simpsons = array();' zaraz po '

+0

@ AndrewG.Johnson: Tak smutny, jak to czyni mnie, to jest poprawny kod PHP. '$ simpsons [0] = array (" name "=>" Abe "," parent "=> - 1);' po prostu automatycznie utworzy tablicę. Dokumenty: http://www.php.net/manual/en/language.types.array.php#language.types.array.syntax.modifying Jest wysoce odradzany, ale jest ważny. –

Odpowiedz

3

Podkręciłem trochę twój kod. Najwyraźniej po przekazaniu odwołania do tablicy $simpsons jako parametru do funkcji rekursywnej działa we wszystkich wersjach.

$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

Testowane, to działa! http://3v4l.org/aSr6C :-D –

+0

To jest oczywiście odpowiedź, ale zastanawiam się, dlaczego 'global $ simpsons;' powodował błędy. Może to był błąd, który został naprawiony w przeszłości. –

+1

Dzięki, udało mi się zastosować go do pierwotnego problemu (zbieranie kategorii produktów dla dzieci w sklepie internetowym) i działa świetnie, prawdopodobnie w odpowiedni sposób, aby to zrobić w pierwszej kolejności, zamiast ogłaszać globalne vars lewo i prawo – L84

8

Nie jestem pewien, co się zmieniło, że aby rozpocząć pracę w 5.2, ale tablica ma tylko jeden wskaźnik wewnętrzny (to, co jest wykorzystywane przez foreach), tak więc w przypadku korzystania z globalną tablicę jak że Wynik widoczny w wersjach do 5.2 ma sens. Rozpoczynasz pętlę foreach, wewnętrzny wskaźnik przesuwa się, następnie wywołujemy rekursywnie get_children, uruchamiamy kolejną pętlę foreach, a wewnętrzny wskaźnik resetuje się, a następnie iteruje przez tablicę.

Po powrocie do adresata wewnętrzny wskaźnik znajdzie się już na końcu tablicy, a pętla foreach zostanie zakończona. To quote the manual:

Jak foreach polega na wewnętrznej tablicy wskaźnik zmiana go w pętli może prowadzić do nieoczekiwanego zachowania.

Przykładem tego może być użycie foreach w foreach na tej samej tablicy.

Edit znalazłem kilka istotnych raportów o błędach, które zostały oznaczone poprawione w wersji 5.2.1:

Okazuje się, że działa na foreach clone tablicy, więc pętle foreach zagnieżdżania są całkowicie poprawne i to był rzeczywiście błąd, w którym odwołania do tablic nie były klonowane w pętlach foreach) aż do wersji 5.2.1.

+0

Nic dziwnego, że nie mogłem wyjaśnić problemu! :-) – L84

+0

Myślałem, że 'global $ simpsons;' czyni to odniesienie do tej samej tablicy, a zatem tego samego wskaźnika. Ale widziałem, że 'foreach' resetuje wskaźnik, więc założyłem, że to nie problem. Wygląda na to. :-) –

Powiązane problemy