KomponentenFileSystemWatcher

FileSystemWatcher: Dateisystemüberwachung ​

Was ist FileSystemWatcher ​

Async\FileSystemWatcher ist ein persistenter Beobachter für Änderungen an Dateien und Verzeichnissen. Im Gegensatz zu einmaligen Ansätzen läuft FileSystemWatcher kontinuierlich und liefert Ereignisse über die Standard-foreach-Iteration:

php
<?php
use Async\FileSystemWatcher;

$watcher = new FileSystemWatcher('/path/to/dir');

foreach ($watcher as $event) {
    echo "{$event->filename}: renamed={$event->renamed}, changed={$event->changed}\n";
}
?>

Die Iteration suspendiert die Coroutine automatisch, wenn der Puffer leer ist, und setzt sie fort, wenn ein neues Ereignis eintrifft.

FileSystemEvent ​

Jedes Ereignis ist ein Async\FileSystemEvent-Objekt mit vier readonly-Eigenschaften:

EigenschaftTypBeschreibung
pathstringDer an den FileSystemWatcher-Konstruktor übergebene Pfad
filename?stringDer Name der Datei, die das Ereignis ausgelöst hat (kann null sein)
renamedbooltrue -- Datei wurde erstellt, gelöscht oder umbenannt
changedbooltrue -- Dateiinhalt wurde geändert

Zwei Pufferungsmodi ​

Coalesce (Standard) ​

Im Coalesce-Modus werden Ereignisse nach dem Schlüssel path/filename gruppiert. Wenn sich eine Datei mehrmals geändert hat, bevor der Iterator sie verarbeitet hat, bleibt nur ein Ereignis mit zusammengeführten Flags im Puffer:

php
<?php
use Async\FileSystemWatcher;

// coalesce: true -- Standard
$watcher = new FileSystemWatcher('/tmp/dir');
?>

Dies ist optimal für typische Szenarien: Hot-Reload, Neuaufbau bei Konfigurationsänderungen, Synchronisation.

Raw ​

Im Raw-Modus wird jedes Ereignis vom Betriebssystem als separates Element in einem Ringpuffer gespeichert:

php
<?php
use Async\FileSystemWatcher;

$watcher = new FileSystemWatcher('/tmp/dir', coalesce: false);
?>

Geeignet, wenn die genaue Reihenfolge und Anzahl der Ereignisse wichtig ist -- Auditing, Logging, Replikation.

Konstruktor ​

php
new FileSystemWatcher(
    string $path,
    bool $recursive = false,
    bool $coalesce = true
)

path -- Pfad zu einer Datei oder einem Verzeichnis. Wenn der Pfad nicht existiert, wird ein Error geworfen.

recursive -- wenn true, werden auch verschachtelte Verzeichnisse überwacht.

coalesce -- Pufferungsmodus: true -- Event-Zusammenführung (HashTable), false -- alle Events (Ringpuffer).

Die Überwachung beginnt sofort bei der Objekterstellung. Ereignisse werden auch vor Beginn der Iteration gepuffert.

Lebenszyklus ​

close() ​

Stoppt die Überwachung. Die aktuelle Iteration endet nach Verarbeitung der verbleibenden Ereignisse im Puffer. Idempotent -- wiederholte Aufrufe sind sicher.

php
<?php
$watcher->close();
?>

isClosed() ​

php
<?php
$watcher->isClosed(); // bool
?>

Automatisches Schließen ​

Wenn das FileSystemWatcher-Objekt zerstört wird (den Gültigkeitsbereich verlässt), wird die Überwachung automatisch gestoppt.

Beispiele ​

Hot-Reload der Konfiguration ​

php
<?php
use Async\FileSystemWatcher;
use function Async\spawn;

spawn(function() {
    $watcher = new FileSystemWatcher('/etc/myapp', recursive: true);

    foreach ($watcher as $event) {
        if (str_ends_with($event->filename ?? '', '.yml')) {
            echo "Konfiguration geändert: {$event->filename}\n";
            reloadConfig();
        }
    }
});
?>

Zeitlich begrenzte Überwachung ​

php
<?php
use Async\FileSystemWatcher;
use function Async\spawn;
use function Async\delay;

$watcher = new FileSystemWatcher('/tmp/uploads');

spawn(function() use ($watcher) {
    delay(30_000);
    $watcher->close();
});

foreach ($watcher as $event) {
    processUpload($event->filename);
}

echo "Überwachung beendet\n";
?>

Überwachung mehrerer Verzeichnisse ​

php
<?php
use Async\FileSystemWatcher;
use function Async\spawn;

$dirs = ['/var/log/app', '/var/log/nginx', '/var/log/postgres'];

foreach ($dirs as $dir) {
    spawn(function() use ($dir) {
        $watcher = new FileSystemWatcher($dir);

        foreach ($watcher as $event) {
            echo "[{$dir}] {$event->filename}\n";
        }
    });
}
?>

Raw-Modus für Auditing ​

php
<?php
use Async\FileSystemWatcher;
use function Async\spawn;

spawn(function() {
    $watcher = new FileSystemWatcher('/secure/data', coalesce: false);

    foreach ($watcher as $event) {
        $type = $event->renamed ? 'RENAME' : 'CHANGE';
        auditLog("[{$type}] {$event->path}/{$event->filename}");
    }
});
?>

Abbruch über Scope ​

FileSystemWatcher wird korrekt beendet, wenn der Scope abgebrochen wird:

php
<?php
use Async\FileSystemWatcher;
use function Async\spawn;
use function Async\delay;

spawn(function() {
    $watcher = new FileSystemWatcher('/tmp/test');

    spawn(function() use ($watcher) {
        foreach ($watcher as $event) {
            echo "{$event->filename}\n";
        }
        echo "Iteration beendet\n";
    });

    delay(5000);
    $watcher->close();
});
?>

Siehe auch ​