Einführung in die asynchrone Programmierung in PHP
\n\nTraditionelles PHP arbeitet synchron: Jede Operation wird nacheinander ausgeführt. Wenn ein Skript eine HTTP-Anfrage senden oder eine Datei lesen muss, wartet es auf den Abschluss der Operation und blockiert dabei die Ausführung des gesamten Codes. Für Webanwendungen mit hoher Last wird dies zum Engpass. Asynchrone Programmierung löst dieses Problem, indem sie die gleichzeitige Ausführung mehrerer Aufgaben ohne Blockierung des Hauptthreads ermöglicht.
\n\nIn diesem Leitfaden werden wir untersuchen, wie Asynchronität in PHP funktioniert, welche Werkzeuge verfügbar sind und wie man sie in der Praxis einsetzt. Sie erfahren etwas über Generatoren, die Bibliotheken ReactPHP und Swoole sowie über die neuen Möglichkeiten von PHP 8.1 – Fiber.
\n\nGrundlagen der asynchronen Programmierung
\n\nWas ist Asynchronität und warum wird sie benötigt?
\n\nStellen Sie sich vor, Sie bereiten das Frühstück zu. Der synchrone Ansatz: Sie stellen den Wasserkocher an, warten, bis das Wasser kocht, und beginnen dann mit dem Braten der Eier. Der asynchrone Ansatz: Sie stellen den Wasserkocher an und bereiten parallel das Rührei zu, während das Wasser erhitzt wird. In PHP bedeutet dies, dass Sie anstatt auf eine Antwort von der Datenbank oder einer externen API zu warten, anderen Code ausführen können.
\n\nDie wichtigsten Vorteile des asynchronen Ansatzes:
\n- \n
- Leistungssteigerung bei I/O-Operationen (Netzwerk, Festplatten, Datenbanken) \n
- Einsparung von Serverressourcen – weniger Threads verarbeiten mehr Anfragen \n
- Möglichkeit zur Erstellung von Echtzeitanwendungen (Chats, Benachrichtigungen, Streaming) \n
Das Problem des synchronen Codes
\n\nBetrachten wir ein klassisches Beispiel: das Abrufen von Daten von zwei entfernten APIs. Synchroner Code wird nacheinander ausgeführt:
\n\n<?php\nfunction fetchData($url) {\n $ch = curl_init($url);\n curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n $result = curl_exec($ch); // Blockierung während der Anfrage\n curl_close($ch);\n return $result;\n}\n\n$start = microtime(true);\n$data1 = fetchData('https://api.example.com/users');\n$data2 = fetchData('https://api.example.com/posts');\necho "Zeit: " . (microtime(true) - $start);\n?>\n\nWenn jede Anfrage 2 Sekunden dauert, beträgt die Gesamtausführungszeit 4 Sekunden, obwohl wir die Anfragen parallel ausführen könnten.
\n\nWerkzeuge für Asynchronität in PHP
\n\n1. Generatoren (yield) – leichte Asynchronität
\n\nGeneratoren wurden in PHP 5.5 eingeführt und ermöglichen die Erstellung von Funktionen, die ihre Ausführung anhalten und die Kontrolle an den aufrufenden Code zurückgeben können. Dies ist die Grundlage für die Erstellung von Coroutinen.
\n\n<?php\nfunction generator() {\n echo "Start des Generators\\n";\n yield 1;\n echo "Nach dem ersten yield\\n";\n yield 2;\n echo "Ende\\n";\n}\n\n$gen = generator();\nforeach ($gen as $value) {\n echo "Erhalten: $value\\n";\n}\n?>\n\nGeneratoren können verwendet werden, um nicht-blockierende Operationen in Verbindung mit einer Ereignisschleife zu organisieren. Für vollständige Asynchronität reicht dies jedoch nicht aus – eine Bibliothek ist erforderlich.
\n\n2. ReactPHP – ereignisorientierte Bibliothek
\n\nReactPHP ist eine beliebte Bibliothek für asynchrone Programmierung. Sie bietet eine Ereignisschleife (Event Loop), nicht-blockierende Sockets, einen HTTP-Client und -Server. Installation über Composer:
\n\ncomposer require react/event-loop react/http\n\nBeispiel einer asynchronen HTTP-Anfrage:
\n\n<?php\nrequire 'vendor/autoload.php';\n\nuse React\\EventLoop\\Factory;\nuse React\\HttpClient\\Client;\nuse React\\HttpClient\\Response;\n\n$loop = Factory::create();\n$client = new Client($loop);\n\n$request = $client->request('GET', 'https://api.example.com/data');\n$request->on('response', function (Response $response) {\n $response->on('data', function ($chunk) {\n echo "Fragment erhalten: " . strlen($chunk) . " Bytes\\n";\n });\n $response->on('end', function () {\n echo "Anfrage abgeschlossen\\n";\n });\n});\n$request->end();\n\necho "Anfrage gesendet, warte...\\n";\n$loop->run();\n?