Signatur
Beschreibung
pcntl_fork() ist die PHP-Schnittstelle zum POSIX-fork()-Systemaufruf. Nach dem Aufruf existieren zwei nahezu identische Prozesse: der Elternprozess erhält als Rückgabewert die PID des neu erzeugten Kindprozesses, während der Kindprozess den Wert 0 zurückbekommt. Bei einem Fehler wird -1 zurückgegeben und kein Kindprozess erzeugt.
Ein typischer Einsatz ist die Parallelverarbeitung: Ein CLI-Skript kann mehrere unabhängige Aufgaben gleichzeitig abarbeiten, ohne auf externe Frameworks angewiesen zu sein. Beispielsweise können Batch-Jobs, Bild-Rendering oder intensive Berechnungen auf mehrere Kinder verteilt werden.
Wichtig ist, dass nach dem Fork beide Prozesse an exakt der gleichen Stelle im Programmcode weiterlaufen, aber in getrennten Adressräumen. Datenbankverbindungen, Datei-Handles und andere Ressourcen werden kopiert, nicht geteilt – dies kann zu unerwarteten Verhaltensweisen führen (z. B. doppelte Schreibvorgänge), weshalb Ressourcen häufig erst nach dem Fork geöffnet werden sollten.
pcntl_fork() steht nur auf POSIX-kompatiblen Betriebssystemen (Linux, macOS) zur Verfügung und funktioniert nicht unter Windows. Außerdem ist es ausschließlich für die CLI-SAPI geeignet; in Web-SAPIs (Apache-Modul, PHP-FPM) kann es zu kritischen Problemen führen.
Rückgabewert
Gibt im Elternprozess die PID (positive Ganzzahl) des erzeugten Kindprozesses zurück, im Kindprozess den Wert 0. Bei einem Fehler wird -1 zurückgegeben und kein Kindprozess erzeugt.
Beispiele
Einfacher Fork mit Eltern-/Kind-Unterscheidung
<?php
$pid = pcntl_fork();
if ($pid === -1) {
die('Fork fehlgeschlagen!');
} elseif ($pid === 0) {
// Dieser Block läuft im Kindprozess
echo "Kindprozess: PID = " . getmypid() . PHP_EOL;
exit(0);
} else {
// Dieser Block läuft im Elternprozess
echo "Elternprozess: PID = " . getmypid() . ", Kind-PID = $pid" . PHP_EOL;
// Auf Beendigung des Kindes warten
pcntl_waitpid($pid, $status);
echo "Kind beendet mit Status: " . pcntl_wexitstatus($status) . PHP_EOL;
}
Parallele Batch-Verarbeitung mit mehreren Kindprozessen
<?php
$aufgaben = ['Aufgabe A', 'Aufgabe B', 'Aufgabe C'];
$kinder = [];
foreach ($aufgaben as $aufgabe) {
$pid = pcntl_fork();
if ($pid === -1) {
die('Fork fehlgeschlagen!');
} elseif ($pid === 0) {
// Kindprozess: Aufgabe simulieren
echo "[Kind " . getmypid() . "] Verarbeite: $aufgabe" . PHP_EOL;
sleep(1); // Simulierte Arbeit
exit(0);
} else {
// Elternprozess: PID merken
$kinder[] = $pid;
}
}
// Elternprozess wartet auf alle Kinder
foreach ($kinder as $kindPid) {
pcntl_waitpid($kindPid, $status);
echo "[Eltern] Kind $kindPid abgeschlossen." . PHP_EOL;
}
echo "Alle Aufgaben erledigt." . PHP_EOL;
// Wichtig · Fallstricke
Zombie-Prozesse: Wird pcntl_waitpid() oder pcntl_wait() nicht aufgerufen, verbleiben beendete Kindprozesse als Zombie-Prozesse in der Prozesstabelle, bis der Elternprozess endet. Bei lang laufenden Elternprozessen kann dies die Prozesstabelle erschöpfen.
Ressourcen nach dem Fork: Geöffnete Datenbankverbindungen (z. B. PDO, MySQLi), Sockets oder Datei-Handles werden in beiden Prozessen als Kopie geführt. Das gemeinsame Nutzen führt häufig zu Fehlern oder Datenverlust. Verbindungen sollten nach dem Fork im Kindprozess neu aufgebaut werden.
Plattformabhängigkeit: Die Funktion ist nur verfügbar, wenn PHP mit --enable-pcntl kompiliert wurde und das Betriebssystem POSIX-fork() unterstützt. Unter Windows ist sie nicht verfügbar.
Web-SAPIs: Der Einsatz in Web-SAPIs (Apache, PHP-FPM) ist gefährlich und nicht empfohlen, da geteilte Ressourcen des Web-Servers korrumpiert werden können.