Problem mit rekursiver Funktion

visiondpc

Erfahrenes Mitglied
Hallo.
Ich würde gerne ein Menü, das in einen DB hinterlegt ist rekursiv auslesen und als String in eine Variable schreiben. Wenn ich die einzelnen Punkte in der Funktion über echo ausgebe funktioniertes problemlos. Wenn ich aber versuche einen String zu erzeugen wird die Variable ständig überschrieben und ich bekomme nur die erste Ebene angezeigt. Ich verstehe zwar warum das so ist, aber ich habe leider kein Idee wie ich das Problem lösen könnte. Es wäre super, wenn mir da jemand auf die Sprünge helfen könnte.

Ich habe das ganze mal mit 4 Datensätzen getestet.
Link_1 (parent_id = 0)
Link_1.1 (parent_id = Link1)
Link_1.1.1 (parent_id = Link1.1)
Link_2 (parent_id = 0)

PHP:
function get_menu($parent_id, $level=1, $menu_str="")
{
	$QUERY = mysql_query("SELECT * FROM dcm1_sites WHERE site_parent_id='".$parent_id."'");
	while($result = mysql_fetch_array($QUERY))
	{
		$menu_str .= $result[site_name]." ".$level."<br />";
		get_menu($result[site_id], $level+1, $menu_str);
	}
	return($menu_str);

	echo get_menu(0)
}
 
Zuletzt bearbeitet:
Ich hab mir das noch nicht richtig angeschaut, ehrlich gesagt hab ich keine Lust grad zu denken :D Aber was mir aufgefallen ist:

Du rufst die Funktion mit 4 Argumenten auf, obwohl sie nur 3 besitzt. Und woher kommt zB die Variable $menu_id?
Vielleicht hilft dir das ja schon weiter, ich bin ja wie gesagt zu faul zum denken ;)
 
Ups mein Fehler. Ich hab das Skript hier der Übersicht halber auf das wesentliche verkürzt. Normalerweise werden die Links noch geparst und dafür brauch ich die Variable um das passende Template zuzuordnen. Ich hatte nur vergessen die im zweiten Aufruf auch zu löschen. Das hab ich aber nachgeholt.
Wie schon geschrieben, wo das Problem liegt weis ich. Nur die Lösung macht mir Kopfzerbrechen.

Wenn ich die Funktion aufrufe ist $menu_str leer. Als nächstes wird der erste Link reingeschrieben und die Funktion erneut aufgerufen um die zweite Ebene zu schreiben.
Wenn wir dann aber an der Stelle sind, wo Link_2 in die Variable geschrieben wird, wird der natürlich an die Variable angehängt, die zuerst übergeben wurde und da steht bisher nur Link_1 drin.

Mit echo drin sieht das dann folgendermaßen aus.

Aufruf 1:
Link_1

Aufruf 2:
Link_1
Link_1.1

Aufruf 3:
Link_1
Link_1.1
Link_1.1.1

Zurück zum ersten Aufruf weil unter 1 nichts mehr kommt:
Link_1
Link_2
 
Sagt dir der Ausruck "Gültigkeitsbereich" etwas? Denn genau das scheint dein Problem zu sein.
Entweder
PHP:
$menu_str = '';

function get_menu($parent_id, $level=1, $menu_str="")
{
    // auf globales und nicht interne Referenz zurückgreifen
    global $menu_str;

    $QUERY = mysql_query("SELECT * FROM dcm1_sites WHERE site_parent_id='".$parent_id."'");
    while($result = mysql_fetch_array($QUERY))
    {
        $menu_str .= $result[site_name]." ".$level."<br />";
        get_menu($result[site_id], $level+1, $menu_str);
    }
    return($menu_str);
}
oder
PHP:
function get_menu($parent_id, $level=1, $menu_str="")
{
    $QUERY = mysql_query("SELECT * FROM dcm1_sites WHERE site_parent_id='".$parent_id."'");
    while($result = mysql_fetch_array($QUERY))
    {
        // zurückgegebenen String anhängen und zurückgeben
        $menu_str = $result[site_name]." ".$level."<br />" . get_menu($result[site_id], $level+1, $menu_str);
    }
    return($menu_str);
}

Die wichtigen Passagen hab ich mal mit einer Kommentarzeile versehen.
Was genau ist das Problem? Innerhalb einer Funktion deklarierte Variablen können nur von der Funktion benutzt werden. Höhergelegene Wertebereiche, wie zB main (also alles) haben darauf keinen direkten Zugriff, und andersrum gilt es ebenso. Was funktioniert, ist die Deklaration eines globalen Wertes innerhalb der Funktion (Gültigkeitsbereich für entsprechenden Bezeichner wird auf main & children gesetzt) oder die Deklaration eines statischen Werts:

PHP:
function get_menu($parent_id, $level=1, $menu_str="")
{
    static $menu_str = '';

    $QUERY = mysql_query("SELECT * FROM dcm1_sites WHERE site_parent_id='".$parent_id."'");
    while($result = mysql_fetch_array($QUERY))
    {
        $menu_str .= $result[site_name]." ".$level."<br />";
        get_menu($result[site_id], $level+1, $menu_str);
    }
    return($menu_str);
}

Mehr dazu findest du auch in der PHP Dokumentation zum Thema Gültigkeitsbereich einer Variable.

Ein Ratschlag jedoch zum Thema rekursive SQL-Query-Aufrufe: Finger davon und eine geeignetere Methode verwenden, wie zB Nested Sets (einfach mal in eine Suchmaschine deiner Wahl tippen) oder andere Wege, die die Rekursion ersparen.
 
Danke für die Hilfe.
Das mit den rekursiven SQL-Abfragen stimmt schon. Wenn man da mal 30 Kategorien zusammen hat wird das auch bestimmt einiges an Ladezeit beanspruchen und das ist natürlich nicht so toll. Das mit den Nested Sets muss ich mir mal in Ruhe anschauen. Davon hab ich bisher noch hie gehört aber s scheint da eine menge gute Artikel im netz drüber zu geben sagt Google.
 
Zurück