2013-08-21 13 views
5

Questo mi sta facendo impazzire. Le funzioni ricorsive sembrano funzionare diversamente in 5.4.4 e 5.1.6 (server di hosting di un client su cui non ho alcun controllo). Non posso davvero spiegare se non con esempio:Le funzioni ricorsive PHP funzionano in modo diverso nelle diverse versioni?

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

Sulla PHP 5.4.4 l'uscita è

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

mentre sul PHP 5.1.6 l'uscita è

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

I Non sono bravo con la terminologia quindi non posso spiegare cosa sta succedendo (è come nella 5.1.6 la funzione chiamata cambia il parametro della funzione chiamante anche quando la funzione chiamata termina), ma ho provato questo in sandbox PHP online su questi due versi Ons e il problema è identico - non è specifico per la mia configurazione o l'installazione del server di hosting.

+1

Problema confermato: http://3v4l.org/n1mVc –

+1

Non si definisce mai $ simpson come un array che è la prima bandiera rossa per me. Se si aggiunge '$ simpsons = array();' immediatamente dopo '

+0

@ AndrewG.Johnson: Per quanto mi rattrista, è un codice PHP valido. '$ simpsons [0] = array (" name "=>" Abe "," parent "=> - 1);' creerà automaticamente una matrice. Documenti: http://www.php.net/manual/en/language.types.array.php#language.types.array.syntax.modifying È altamente sconsigliato, ma è valido. –

risposta

3

Ho modificato leggermente il codice. Apparentemente quando si passa il riferimento dell'array $simpsons come parametro alla funzione ricorsiva, funziona in tutte le versioni.

$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

Testato, funziona! http://3v4l.org/aSr6C :-D –

+0

Questa è chiaramente la risposta, ma mi chiedo perché 'global $ simpsons;' stava causando errori. Forse è stato un errore che è stato risolto in passato. –

+1

Grazie, sono riuscito ad applicarlo al problema originale (raccolta di categorie figlio di prodotti su un negozio online) e funziona benissimo, probabilmente il modo giusto per farlo in primo luogo invece di dichiarare vars globali a destra ea sinistra – L84

8

non sono sicuro che cosa è cambiato per fare che iniziare a lavorare in 5.2, ma una matrice ha un solo puntatore interno (che è quello che viene utilizzato da foreach), in modo che quando si utilizza una matrice globale come quello della risultato che vedi nelle versioni fino a 5.2 ha molto senso. Si avvia un ciclo foreach, il puntatore interno avanza, quindi si richiama in modo ricorsivo get_children, si avvia un altro ciclo foreach e il puntatore interno si reimposta e quindi scorre attraverso l'array.

Quando si ritorna al callee, il puntatore interno sarà già alla fine della matrice e il ciclo foreach verrà completato. To quote the manual:

Poiché foreach si basa sul puntatore dell'array interno cambiandolo all'interno del loop può portare a un comportamento imprevisto.

L'utilizzo di foreach all'interno di un foreach sullo stesso array è un esempio.

Edit ho trovato un paio di segnalazioni di bug rilevanti che sono stati contrassegnati risolto nella versione 5.2.1:

Si scopre che foreach opera su una clone dell'array, quindi l'annidamento di cicli foreach è perfettamente valido e questo era davvero un bug, in cui i riferimenti di array non venivano clonati in cicli foreach) fino alla versione 5.2.1.

+0

Non c'è da meravigliarsi se non ho potuto spiegare il problema! :-) – L84

+0

Stavo pensando che 'global $ simpson;' stava facendo riferimento allo stesso array e quindi allo stesso puntatore. Ma ho visto che 'foreach' reimposta il puntatore, quindi ho pensato che non fosse questo il problema. Sembra che fosse. :-) –

Problemi correlati