Einführung in die asynchrone Programmierung in PHP
Traditionell ist PHP eine synchrone Sprache: Jede Anfrage wird sequenziell ausgeführt und blockiert die Ausführung, bis die Ein-/Ausgabe-Operation abgeschlossen ist. Mit steigenden Leistungsanforderungen an Webanwendungen ist die asynchrone Programmierung in PHP jedoch notwendig geworden. Sie ermöglicht die Verarbeitung tausender gleichzeitiger Verbindungen, die Ausführung paralleler Aufgaben und die effiziente Nutzung von Systemressourcen.
In diesem Leitfaden betrachten wir praktische Ansätze zur asynchronen Programmierung in PHP: von grundlegenden Konzepten bis hin zu realen Beispielen mit modernen Bibliotheken und den integrierten Funktionen von PHP 8.1+.
Grundlagen der Asynchronität: Event Loop und nicht-blockierende Ein-/Ausgabe
Im Kern jeder asynchronen Anwendung steht der Event Loop (Ereignisschleife). Dies ist eine Endlosschleife, die auf neue Ereignisse (Anfragen, Daten aus der Datenbank, Dateien) prüft und deren Verarbeitung ohne Blockierung des Hauptthreads verteilt.
Synchroner Code funktioniert so:
<?php// Blockierende Operation - das Programm wartet 5 Sekundensleep(5);echo "5 Sekunden vergangen";// Der folgende Code wird erst nach sleep ausgeführtecho "Diese Nachricht erscheint nach 5 Sekunden";?>Asynchroner Ansatz mit ReactPHP:
<?phprequire 'vendor/autoload.php';
use React\\EventLoop\\Factory;use React\\Promise\\Promise;
$loop = Factory::create();
// Nicht-blockierender Timer$loop->addTimer(5, function () { echo "5 Sekunden vergangen";});
echo "Diese Nachricht erscheint sofort";$loop->run();?>In der asynchronen Variante wird der Code nicht blockiert: Die Nachricht wird sofort ausgegeben, während der Timer im Hintergrund ausgelöst wird.
Praktischer Leitfaden: Vom Einfachen zum Komplexen
1. Verwendung von Fiber (PHP 8.1+)
Fiber ist ein integrierter Coroutinen-Mechanismus, der in PHP 8.1 eingeführt wurde. Er ermöglicht es, die Ausführung einer Funktion zu unterbrechen und später ohne Blockierung des Threads fortzusetzen.
Beispiel für die parallele Ausführung von Aufgaben mit Fiber:
<?phpfunction fetchData(string $url): Fiber{ return new Fiber(function () use ($url) { // Simulation einer HTTP-Anfrage $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 5); // Fiber anhalten Fiber::suspend(curl_exec($ch)); curl_close($ch); });}
// Mehrere Fiber erstellen$fiber1 = fetchData('https://api.example.com/data1');$fiber2 = fetchData('https://api.example.com/data2');
// Fiber starten$result1 = $fiber1->start();$result2 = $fiber2->start();
// Ausführung fortsetzen$result1 = $fiber1->resume();$result2 = $fiber2->resume();
echo "Ergebnis 1: " . $result1 . "";echo "Ergebnis 2: " . $result2 . "";?>2. Asynchrone Datenbankarbeit mit Amp
Amp ist eine leistungsstarke Bibliothek für asynchrone Programmierung. Betrachten wir ein Beispiel für eine asynchrone MySQL-Verbindung:
<?phprequire 'vendor/autoload.php';
use Amp\\Loop;use Amp\\Mysql\\ConnectionConfig;use Amp\\Mysql\\Pool;
Loop::run(function () { $config = ConnectionConfig::fromString( "host=localhost user=root password=secret db=test" ); $pool = new Pool($config); // Asynchrone Abfrage - blockiert die Ausführung nicht $promise1 = $pool->query("SELECT SLEEP(2)"); $promise2 = $pool->query("SELECT 1 + 1 AS result"); // Beide Abfragen werden parallel ausgeführt $result1 = yield $promise1; $result2 = yield $promise2; foreach ($result2 as $row) { echo "Ergebnis: " . $row['result'] . ""; } $pool->close();});?>3. Erstellen eines asynchronen HTTP-Servers mit ReactPHP
Vollständig