Signatur
Beschreibung
EvChild ist ein Watcher aus der ev-PECL-Erweiterung und reagiert auf Statusänderungen von Kindprozessen – insbesondere auf deren Beendigung. Intern nutzt er den POSIX-Mechanismus SIGCHLD, um effizient auf Prozess-Events zu warten, ohne aktiv pollen zu müssen.
Typische Einsatzgebiete sind asynchrone Prozessverwaltung: Ein übergeordneter Prozess startet mit pcntl_fork() einen oder mehrere Kindprozesse und verwendet EvChild, um zu erfahren, wann diese enden und mit welchem Exit-Code. So lassen sich Ressourcen korrekt freigeben und nachfolgende Schritte einleiten.
Der Watcher wird immer im Standard-Event-Loop (EvLoop::defaultLoop()) ausgeführt, da SIGCHLD-Signalverarbeitung nur dort zuverlässig funktioniert. Ein EvChild-Watcher im Kontext eines anderen Loops ist nicht sinnvoll.
Innerhalb des Callbacks stehen über das $watcher-Objekt wichtige Eigenschaften zur Verfügung: $watcher->rpid enthält die tatsächliche PID des beendeten Kindprozesses und $watcher->rstatus den Raw-Exit-Status, der mit den pcntl_*-Funktionen (z. B. pcntl_wexitstatus()) ausgewertet werden kann.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $pid Pflicht | int | PID des zu überwachenden Kindprozesses. Der Wert 0 überwacht alle Kindprozesse des aktuellen Prozesses. |
|
| $trace Pflicht | bool | Wenn true, wird der Watcher auch bei gestoppten (nicht nur bei beendeten) Kindprozessen ausgelöst (entspricht WUNTRACED in POSIX). Normalerweise false. |
|
| $callback Pflicht | callable | Callback-Funktion, die aufgerufen wird, wenn der Kindprozess seinen Status ändert. Signatur: function(EvChild $watcher, int $revents): void. |
|
| $data | mixed | null | Beliebige benutzerdefinierte Daten, die dem Watcher beigefügt und im Callback über $watcher->data abgerufen werden können. |
| $priority | int | 0 | Priorität des Watchers. Höhere Werte bedeuten höhere Priorität. Gültige Werte liegen im Bereich Ev::MINPRI bis Ev::MAXPRI. |
Rückgabewert
Beispiele
Kindprozess starten und Beendigung überwachen
<?php
// Nur im Default-Loop möglich!
$pid = pcntl_fork();
if ($pid === 0) {
// Kindprozess: simuliert Arbeit und beendet sich
sleep(1);
exit(42);
}
if ($pid > 0) {
// Elternprozess: EvChild-Watcher anlegen
$watcher = new EvChild(
$pid,
false,
function (EvChild $w, int $revents) {
echo "Kindprozess PID {$w->rpid} beendet." . PHP_EOL;
$exitCode = pcntl_wexitstatus($w->rstatus);
echo "Exit-Code: {$exitCode}" . PHP_EOL;
$w->stop(); // Watcher stoppen
Ev::stop(); // Event-Loop beenden
}
);
Ev::run(); // Event-Loop starten
}
Alle Kindprozesse überwachen (pid = 0)
<?php
$pids = [];
// Mehrere Kindprozesse starten
for ($i = 0; $i < 3; $i++) {
$pid = pcntl_fork();
if ($pid === 0) {
sleep(rand(1, 3));
exit($i + 1);
}
$pids[] = $pid;
}
$finished = 0;
$total = count($pids);
// pid=0 => alle Kindprozesse überwachen
$watcher = new EvChild(
0,
false,
function (EvChild $w, int $revents) use (&$finished, $total) {
$exit = pcntl_wexitstatus($w->rstatus);
echo "Kind-PID {$w->rpid} beendet mit Exit-Code {$exit}" . PHP_EOL;
$finished++;
if ($finished >= $total) {
$w->stop();
Ev::stop();
}
}
);
Ev::run();
// Wichtig · Fallstricke
Achtung: EvChild-Watcher dürfen ausschließlich im Standard-Event-Loop (EvLoop::defaultLoop() bzw. über die statische Ev::run()-API) verwendet werden. In benutzerdefinierten Loops ist das Verhalten undefiniert, da die SIGCHLD-Verarbeitung global ist.
Der rstatus-Wert ist der rohe POSIX-Wait-Status. Für eine sinnvolle Auswertung sollten pcntl_wifexited(), pcntl_wexitstatus(), pcntl_wifsignaled() und pcntl_wtermsig() verwendet werden.
Die ev-Erweiterung muss über PECL installiert sein (pecl install ev). Sie steht nicht standardmäßig in PHP zur Verfügung.