Start · Sprachen · PHP · Referenz · RecursiveCallbackFilterIterator

RecursiveCallbackFilterIterator

Klasse

Filtert einen <code>RecursiveIterator</code> anhand eines benutzerdefinierten Callbacks und unterstützt dabei die rekursive Traversierung von Baumstrukturen.

seit PHP 5.4.0 Kategorie: oop

Signatur

class RecursiveCallbackFilterIterator extends CallbackFilterIterator implements RecursiveIterator

Beschreibung

RecursiveCallbackFilterIterator erweitert CallbackFilterIterator um die Fähigkeit, rekursive Iteratoren (z. B. RecursiveDirectoryIterator oder RecursiveArrayIterator) zu filtern. Der übergebene Callback entscheidet für jedes Element, ob es in die Ausgabe einbezogen werden soll. Im Gegensatz zum einfachen CallbackFilterIterator werden auch Kindknoten rekursiv gefiltert, wenn man den Iterator in einen RecursiveIteratorIterator einbettet.

Der Callback erhält drei Argumente: den aktuellen Wert, den aktuellen Schlüssel und den Iterator selbst. Er muss true zurückgeben, damit das Element sichtbar bleibt. Wichtig: Damit der Abstieg in Unterverzeichnisse oder Kindknoten überhaupt stattfindet, muss der Callback für Elemente mit Kindern ebenfalls true zurückgeben – andernfalls werden ganze Teilbäume übersprungen.

Typische Einsatzgebiete sind das Filtern von Verzeichnisbäumen (z. B. nur bestimmte Dateiendungen anzeigen), das Durchsuchen verschachtelter Arrays nach Kriterien oder das Einschränken einer beliebigen Baumstruktur auf relevante Knoten, ohne eine eigene Iterator-Unterklasse schreiben zu müssen.

Durch die Kombination mit RecursiveIteratorIterator (Modus LEAVES_ONLY, SELF_FIRST oder CHILD_FIRST) lässt sich der gefilterte Baum anschließend flach iterieren.

Parameter

Name Typ Default Beschreibung
$iterator Pflicht RecursiveIterator Der zu filternde rekursive Iterator, z. B. ein RecursiveDirectoryIterator oder RecursiveArrayIterator.
$callback Pflicht callable Ein Callable mit der Signatur function(mixed $value, mixed $key, RecursiveIterator $iterator): bool. Gibt true zurück, um das aktuelle Element einzuschließen. Damit Kindknoten besucht werden, muss der Callback für Eltern-Elemente mit Kindern ebenfalls true liefern.

Rückgabewert

Typ

Beispiele

PHP-Dateien in einem Verzeichnisbaum filtern

<?php
$directory = new RecursiveDirectoryIterator(
    __DIR__,
    RecursiveDirectoryIterator::SKIP_DOTS
);

$filter = new RecursiveCallbackFilterIterator(
    $directory,
    function (SplFileInfo $current, string $key, RecursiveIterator $iterator): bool {
        // Unterverzeichnisse immer durchsuchen
        if ($current->isDir()) {
            return true;
        }
        // Nur PHP-Dateien zulassen
        return $current->getExtension() === 'php';
    }
);

$iterator = new RecursiveIteratorIterator(
    $filter,
    RecursiveIteratorIterator::SELF_FIRST
);

foreach ($iterator as $file) {
    if ($file->isFile()) {
        echo $file->getPathname() . PHP_EOL;
    }
}
/var/www/html/index.php /var/www/html/src/Controller.php /var/www/html/src/Model.php

Verschachteltes Array nach Wert filtern

<?php
$data = [
    'Deutschland' => [
        'Berlin'  => ['Mitte', 'Prenzlauer Berg', 'Neukölln'],
        'Hamburg' => ['Altona', 'Eimsbüttel'],
    ],
    'Österreich' => [
        'Wien'  => ['Innere Stadt', 'Mariahilf'],
        'Graz'  => ['Lend', 'Jakomini'],
    ],
];

$arrayIterator = new RecursiveArrayIterator($data);

// Nur Einträge anzeigen, die den Buchstaben 'a' (case-insensitive) enthalten
$filter = new RecursiveCallbackFilterIterator(
    $arrayIterator,
    function (mixed $value, mixed $key, RecursiveIterator $iterator) use (&$filter): bool {
        if (is_array($value)) {
            return true; // Unterebenen immer betreten
        }
        return stripos($value, 'a') !== false;
    }
);

$flat = new RecursiveIteratorIterator($filter);

foreach ($flat as $key => $value) {
    echo "$key: $value" . PHP_EOL;
}
0: Prenzlauer Berg 1: Neukölln 0: Altona 1: Eimsbüttel 0: Mariahilf 0: Jakomini

// Wichtig · Fallstricke

Wichtiger Fallstrick: Gibt der Callback für ein Element mit Kindern false zurück, werden alle seine Kindknoten ebenfalls übersprungen – der Iterator steigt dort gar nicht erst ab. Sollen Kindknoten unabhängig vom Eltern-Element erreichbar sein, muss der Callback für Verzeichnisse bzw. Elternknoten immer true liefern.

Der Callback wird bei der Methode hasChildren() nicht erneut aufgerufen; getChildren() gibt automatisch eine neue RecursiveCallbackFilterIterator-Instanz mit demselben Callback zurück, sodass die Filterung auf allen Ebenen konsistent angewendet wird.

Bei sehr tiefen Verzeichnisstrukturen oder großen Arrays sollte die Komplexität des Callbacks gering gehalten werden, da er für jedes Element aufgerufen wird und die Performance bei umfangreichen Bäumen beeinflussen kann.