Signatur
Beschreibung
EvFork ist ein spezieller Watcher der ev-Erweiterung (PECL), der immer dann aktiviert wird, wenn der laufende Prozess eine fork()-Operation durchgeführt hat und der Event-Loop im Kindprozess zum ersten Mal iteriert. Dies ist notwendig, weil viele interne Zustände eines Event-Loops – beispielsweise offene Dateideskriptoren, epoll- oder kqueue-Handles – nach einem fork() im Kindprozess ungültig sind.
Mit einem EvFork-Watcher kann der Entwickler den Event-Loop und damit verbundene Ressourcen im Kindprozess sauber zurücksetzen oder neu initialisieren, bevor der erste reguläre Event-Callback ausgeführt wird. Typische Anwendungen sind das Neuinitialisieren von Datenbankverbindungen, das Schließen von Sockets, die nur dem Elternprozess gehören, oder das Neustarten von Hintergrundthreads.
Die Klasse erbt von EvWatcher und bietet dieselben Steuerungsmethoden (start(), stop(), keepalive() usw.). Im Gegensatz zu anderen Watchern hat EvFork keinen eigenen Beobachtungswert – es gibt keine Datei, keinen Timer oder kein Signal; der einzige Auslöser ist der Post-Fork-Zustand des Loops.
Zu beachten ist, dass EvFork-Callbacks nur im Kindprozess ausgelöst werden und der Elternprozess davon nicht betroffen ist. Das Zurücksetzen des Loops im Kindprozess sollte über EvLoop::defaultLoop() oder die jeweilige Loop-Instanz erfolgen.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $callback Pflicht | callable | Eine aufrufbare Funktion, die nach dem fork() im Kindprozess beim ersten Loop-Durchlauf aufgerufen wird. Signatur: function(EvFork $watcher, int $revents): void. |
|
| $data | mixed | null | Beliebige benutzerdefinierte Daten, die dem Watcher zugeordnet werden und über $watcher->data zugänglich sind. |
| $priority | int | 0 | Priorität des Watchers. Höhere Werte bedeuten frühere Ausführung innerhalb desselben Loop-Durchlaufs. Gültige Werte: Ev::MINPRI bis Ev::MAXPRI. |
Beispiele
Datenbankverbindung nach fork() neu initialisieren
<?php
// Voraussetzung: PECL-Erweiterung 'ev' ist installiert
$forkWatcher = new EvFork(
function (EvFork $watcher, int $revents): void {
// Dieser Code läuft nur im Kindprozess nach fork()
echo "[Kind PID " . posix_getpid() . "] fork() erkannt – Loop und Ressourcen werden neu initialisiert.\n";
// Beispiel: Datenbankverbindung trennen und neu aufbauen
// $db->close();
// $db->connect();
// Loop-Zustand im Kindprozess zurücksetzen
Ev::defaultLoop();
},
null, // keine benutzerdefinierten Daten
Ev::MAXPRI // höchste Priorität, damit es zuerst läuft
);
$pid = pcntl_fork();
if ($pid === 0) {
// Kindprozess: Event-Loop starten
Ev::run(Ev::RUN_ONCE);
exit(0);
} else {
// Elternprozess: auf Kind warten
pcntl_waitpid($pid, $status);
echo "[Eltern PID " . posix_getpid() . "] Kindprozess beendet.\n";
}
EvFork mit einer eigenen Loop-Instanz verwenden
<?php
// Eigene Loop-Instanz (nicht den Default-Loop)
$loop = new EvLoop();
$forkWatcher = $loop->fork(
function (EvFork $watcher, int $revents) use ($loop): void {
echo "Kindprozess PID: " . posix_getpid() . " – eigene Loop-Instanz zurücksetzen.\n";
// Hier können loop-spezifische Ressourcen zurückgesetzt werden
$watcher->stop(); // Watcher deaktivieren, wenn er nur einmalig benötigt wird
}
);
$pid = pcntl_fork();
if ($pid === 0) {
$loop->run(Ev::RUN_ONCE);
exit(0);
}
pcntl_waitpid($pid, $status);
// Wichtig · Fallstricke
Wichtig: EvFork-Watcher werden ausschließlich im Kindprozess ausgelöst. Der Elternprozess empfängt kein Ereignis. Nach einem fork() sollte man im Kindprozess immer alle Ressourcen neu initialisieren, die nicht fork-sicher sind (z. B. Datenbankverbindungen, Mutex-Handles, Netzwerk-Sockets).
Ressourcenkonflikt: Ohne EvFork-Handler können im Kindprozess Doppelschreibungen auf Sockets oder Datenbankverbindungs-Korruptionen auftreten, da Eltern- und Kindprozess dieselben Dateideskriptoren teilen.
Abhängigkeit: Die Klasse steht nur zur Verfügung, wenn die PECL-Erweiterung ev installiert ist (pecl install ev). Sie ist nicht Teil der PHP-Standardinstallation.