Blaubart: Array rekursiv durchsuchen - die Dritte

Beitrag lesen

Tach.

Laß uns die ganze Sache einfach mal schrittweise entwickeln:

Bisher hast du nicht definiert, welche Form genau dein "Pfad" haben soll. Wenn es jeweils der Inhalt von "href" sein soll, kriegst du Probleme mit der oberstern Ebene in deinem Array $entries -- dort existiert nämlich kein Schlüssel "href". Wie soll z. B. das Ergebnis deiner Suche nach "nachrichten" in deinem Beispielarray aussehen?

Umgehen könntest du dieses Problem, indem du $entries einen zusätzlichen Eintrag "href" spendierst, der auch leer sein kann (als root sozusagen). Ob und wie du deine Struktur änderst, bleibt natürlich dir überlassen. Ich würde dir ebenfalls eine Umstrukturierung ans Herz legen, wie sie wahsaga bereits vorschlug. Damit sparst du dir auch bei künftigen Erweiterungen einigen Ärger.

Nun gut ... Ich wähle als Bestandteile der Pfadangabe jetzt einfach mal den (numerischen) Schlüssel des Arrays, da das eindeutig den Weg durch deine Datenstruktur beschreibt. Wenn dir das nicht gefällt, mußt du die Funktion entsprechend abändern.

Genug der Vorrede.

Die Funktion search() soll in einem verschachtelten Array $haystack alle Felder mit Schlüssel $searchKey nach dem Wert $needle durchsuchen. Die Suche bricht nach dem ersten Treffer ab. Als Ergebnis gibt sie einen String zurück, in dem mit Arrayindizes der Pfad zum zutreffenden Element angegeben ist. Die Indizes werden durch ein festgelegte Zeichen $separator voneinander getrennt. Wird nichts gefunden, bleibt der Rückgabestring leer. Dazu folgendes Grundgerüst:

  
function search ($haystack, $needle, $searchKey = "href", $separator = "/") {  
    if (!is_array($haystack)) {  
        return "";  
    }  
  
    foreach ($haystack as $key => $val) {  
        // Inhalt des aktuellen Feldes mit dem Suchbegriff vergleichen  
        if ($key === $searchKey) {  
            // ...  
        }  
        // Kindelemente nach $needle durchsuchen  
        else if (is_array($val)) {  
            // ...  
        }  
        // andere Felder  
        else {  
            // ...  
        }  
    }  
  
    return "";  
}  

Die Fallunterscheidung liefert als erste Möglichkeit einen Schlüssel, der genau dem zu überprüfenden $searchKey entspricht -- bei dir ist das "href". In diesem Fall müssen wir nur überprüfen, ob der zugehörige Wert auch mit $needle übereinstimmt. Falls ja, können wir die Suche beenden und als Ergebnis den Pfad durch das Array zurückgeben, der zum aktuellen Feld führt.

  
// Inhalt des aktuellen Feldes mit dem Suchbegriff vergleichen  
if ($key === $searchKey) {  
    if ($val == $needle) {  
        // $needle im aktuellen Feld gefunden! Suche beenden.  
        return $separator . $key;  
    }  
}  

Als nächster Fall kann ein Feld auftreten, das selber ein Array ist und die Kindelemente des Feldes auf der aktuellen Ebene darstellt. Da wir gerade schon eine Funktion schreiben, die ein verschachteltes Array nach $needle durchsucht, können wir sie einfach auf dieses Array anwenden. ;) Wie oben festgelegt, bleibt der Rückgabewert ein leerer String, falls in dem Array kein passender Wert gefunden wurde. In diesem Fall heißt es "weitersuchen". Ist der Pfad aber nicht leer, wurde in den Kindern etwas gefunden und wir können die Suche abbrechen.

  
// Kindelemente nach $needle durchsuchen  
else if (is_array($val)) {  
    $path = search($val, $needle, $searchKey, $separator);  
    // $needle in einem der Kinder gefunden! Suche beenden.  
    if ($path != "") {  
        return $separator . $key . $path;  
    }  
}  

Alle restlichen Ergebnisse der Fallunterscheidung interessieren uns nicht weiter. In diese Kategorie fallen z. B. die Schlüssel "text" und "title". Der letzte else-Zweig kann also leer bleiben oder gleich ganz gestrichen werden.

Insgesamt sieht das dann so aus:

  
function search ($haystack, $needle, $searchKey = "href", $separator = "/") {  
    if (!is_array($haystack)) {  
        return "";  
    }  
  
    foreach ($haystack as $key => $val) {  
        // Inhalt des aktuellen Feldes mit dem Suchbegriff vergleichen  
        if ($key === $searchKey) {  
            if ($val == $needle) {  
                // $needle im aktuellen Feld gefunden! Suche beenden.  
                return $separator . $key;  
            }  
        }  
        // Kindelemente nach $needle durchsuchen  
        else if (is_array($val)) {  
            $path = search($val, $needle, $searchKey, $separator);  
            // $needle in einem der Kinder gefunden! Suche beenden.  
            if ($path != "") {  
                return $separator . $key . $path;  
            }  
        }  
    }  
  
    return "";  
}  

Auf dein Beispielarray angewandt erhalten wir z. B. folgende Ergebnisse:

  
search($entries, "nachrichten"); // "/0/href"  
search($entries, "nüscht"); // ""  
search($entries, "archiv"); // "/3/2/href"  

Sei dir aber bitte der Tatsache bewußt, daß das eine ziemlich wacklige Angelegenheit werden kann. Die ganze Sache geht z. B. nach hinten los, wenn du aus irgendwelchen Gründen in Felder mit dem Schlüssel "href" ein Array steckst. Überleg dir einfach nochmal, ob es sich nicht doch lohnt, das ganze in einer vernünftigen Klasse zu kapseln, die auch das Erstellen deiner Navigationsstruktur unanfälliger gegen Falscheingaben machen kann!

--
Once is a mistake, twice is jazz.