Die Kernreaktor-Ereignisschleife von ReactPHP, die Bibliotheken für ereignisgesteuerte E/A verwenden können.
Entwicklungsversion: Dieser Zweig enthält den Code für die kommende v3-Version. Den Code der aktuellen stabilen v1-Version finden Sie im
1.x
Zweig.Die kommende Version 3 wird der Weg für die Zukunft dieses Pakets sein. Wir werden Version 1 jedoch weiterhin aktiv für diejenigen unterstützen, die noch nicht über die neueste Version verfügen. Weitere Einzelheiten finden Sie auch in der Installationsanleitung.
Damit asynchrone Bibliotheken interoperabel sind, müssen sie dieselbe Ereignisschleife verwenden. Diese Komponente stellt ein gemeinsames LoopInterface
bereit, auf das jede Bibliothek abzielen kann. Dadurch können sie in derselben Schleife mit einem einzigen run()
-Aufruf verwendet werden, der vom Benutzer gesteuert wird.
Inhaltsverzeichnis
Schnellstart-Beispiel
Verwendung
laufen()
stoppen()
addTimer()
addPeriodicTimer()
cancelTimer()
FutureTick()
addSignal()
removeSignal()
addReadStream()
addWriteStream()
removeReadStream()
removeWriteStream()
StreamSelectLoop
ExtEventLoop
ExtEvLoop
ExtUvLoop
Schleifenmethoden
Schleifen-Autorun
erhalten()
Schleife
Schleifenimplementierungen
LoopInterface
Installieren
Tests
Lizenz
Mehr
Hier ist ein asynchroner HTTP-Server, der nur mit der Ereignisschleife erstellt wurde.
<?phpuse ReactEventLoopLoop;require __DIR__ . '/vendor/autoload.php';$server = stream_socket_server('tcp://127.0.0.1:8080');stream_set_blocking($server, false); Loop::addReadStream($server, function ($server) {$conn = stream_socket_accept($server);$data = "HTTP/1.1 200 OKrnContent-Length: 3rnrnHin"; Loop::addWriteStream($conn, function ($conn) use (&$data) {$geschrieben = fwrite($conn, $data);if ($geschrieben === strlen($data)) {fclose($conn ); Loop::removeWriteStream($conn); } else {$data = substr($data, $geschrieben); } }); }); Loop::addPeriodicTimer(5, function () {$memory = memory_get_usage() / 1024;$formatted = number_format($memory, 3).'K';echo "Aktuelle Speichernutzung: {$formatted}n"; });
Siehe auch die Beispiele.
Typische Anwendungen würden die Loop
Klasse verwenden, um die Standard-Ereignisschleife wie folgt zu verwenden:
use ReactEventLoopLoop;$timer = Loop::addPeriodicTimer(0.1, function () {echo 'Tick' . PHP_EOL; }); Loop::addTimer(1.0, function () use ($timer) { Loop::cancelTimer($timer);echo 'Fertig' . PHP_EOL; });
Alternativ können Sie auch explizit am Anfang eine Ereignisschleifeninstanz erstellen, diese im gesamten Programm wiederverwenden und schließlich am Ende des Programms wie folgt ausführen:
$loop = ReactEventLoopLoop::get();$timer = $loop->addPeriodicTimer(0.1, function () {echo 'Tick' . PHP_EOL; });$loop->addTimer(1.0, function () use ($loop, $timer) {$loop->cancelTimer($timer);echo 'Done' . PHP_EOL; });$loop->run();
Während Ersteres prägnanter ist, ist Letzteres expliziter. In beiden Fällen würde das Programm genau die gleichen Schritte ausführen.
Die Ereignisschleifeninstanz wird am Anfang des Programms erstellt. Dies erfolgt implizit beim ersten Aufruf der Loop
-Klasse (oder durch manuelles Instanziieren einer der Schleifenimplementierungen).
Die Ereignisschleife wird direkt verwendet oder als Instanz an Bibliotheks- und Anwendungscode übergeben. In diesem Beispiel wird ein periodischer Timer in der Ereignisschleife registriert, die einfach alle Sekundenbruchteile Tick
ausgibt, bis ein anderer Timer den periodischen Timer nach einer Sekunde stoppt.
Die Ereignisschleife wird am Ende des Programms ausgeführt. Dies geschieht automatisch bei Verwendung der Loop
Klasse oder explizit mit einem einzelnen run()
-Aufruf am Ende des Programms.
Ab v1.2.0
empfehlen wir dringend die Verwendung der Loop
-Klasse. Die expliziten Schleifenanweisungen sind weiterhin gültig und können in einigen Anwendungen immer noch nützlich sein, insbesondere für eine Übergangsphase hin zum prägnanteren Stil.
Die Loop
-Klasse dient als praktischer globaler Zugriffsmechanismus für die Ereignisschleife.
Die Loop
-Klasse stellt alle Methoden, die auf dem LoopInterface
vorhanden sind, als statische Methoden bereit:
laufen()
stoppen()
addTimer()
addPeriodicTimer()
cancelTimer()
FutureTick()
addSignal()
removeSignal()
addReadStream()
addWriteStream()
removeReadStream()
removeWriteStream()
Wenn Sie mit der Ereignisschleife in Ihrem Anwendungscode arbeiten, ist es oft am einfachsten, wie folgt eine direkte Schnittstelle zu den in der Loop
Klasse definierten statischen Methoden herzustellen:
use ReactEventLoopLoop;$timer = Loop::addPeriodicTimer(0.1, function () {echo 'Tick' . PHP_EOL; }); Loop::addTimer(1.0, function () use ($timer) { Loop::cancelTimer($timer);echo 'Fertig' . PHP_EOL; });
Wenn Sie hingegen mit objektorientierter Programmierung (OOP) und Abhängigkeitsinjektion (DI) vertraut sind, möchten Sie möglicherweise eine Ereignisschleifeninstanz einfügen und Instanzmethoden auf dem LoopInterface
wie folgt aufrufen:
Benutze ReactEventLoopLoop;benutze ReactEventLoopLoopInterface;Klasse Greeter {private $loop;öffentliche Funktion __construct(LoopInterface $loop) {$this->loop = $loop; }öffentliche Funktiongreet(string $name) {$this->loop->addTimer(1.0, function () use ($name) {echo 'Hello ' . $name . '!' . PHP_EOL; }); } }$greeter = new Greeter(Loop::get());$greeter->greet('Alice');$greeter->greet('Bob');
Jeder statische Methodenaufruf wird unverändert an die zugrunde liegende Ereignisschleifeninstanz weitergeleitet, indem intern der Loop::get()
-Aufruf verwendet wird. Weitere Informationen zu den verfügbaren Methoden finden Sie unter LoopInterface
.
Bei Verwendung der Loop
-Klasse wird die Schleife am Ende des Programms automatisch ausgeführt. Das bedeutet, dass im folgenden Beispiel ein Timer geplant und das Programm automatisch ausgeführt wird, bis das Timer-Ereignis ausgelöst wird:
benutze ReactEventLoopLoop; Loop::addTimer(1.0, function () {echo 'Hello' . PHP_EOL; });
Ab v1.2.0
empfehlen wir dringend, die Loop
-Klasse auf diese Weise zu verwenden und alle expliziten run()
-Aufrufe wegzulassen. Aus BC-Gründen ist die explizite run()
Methode immer noch gültig und kann in einigen Anwendungen immer noch nützlich sein, insbesondere für eine Übergangsphase hin zum prägnanteren Stil.
Wenn Sie nicht möchten, dass die Loop
automatisch ausgeführt wird, können Sie sie entweder explizit run()
oder stop()
. Dies kann nützlich sein, wenn Sie einen globalen Ausnahmehandler wie diesen verwenden:
benutze ReactEventLoopLoop; Loop::addTimer(10.0, function () {echo 'Nie passiert'; });set_Exception_handler(function (Throwable $e) {echo 'Error: ' . $e->getMessage() . PHP_EOL; Schleife::stop(); });throw new RuntimeException('Demo');
Die Methode get(): LoopInterface
kann verwendet werden, um die aktuell aktive Ereignisschleifeninstanz abzurufen.
Diese Methode gibt während der gesamten Lebensdauer Ihrer Anwendung immer dieselbe Ereignisschleifeninstanz zurück.
use ReactEventLoopLoop;use ReactEventLoopLoopInterface;$loop = Loop::get();assert($loop exampleof LoopInterface);assert($loop === Loop::get());
Dies ist besonders nützlich, wenn Sie objektorientierte Programmierung (OOP) und Abhängigkeitsinjektion (DI) verwenden. In diesem Fall möchten Sie möglicherweise eine Ereignisschleifeninstanz einfügen und Instanzmethoden auf dem LoopInterface
wie folgt aufrufen:
Benutze ReactEventLoopLoop;benutze ReactEventLoopLoopInterface;Klasse Greeter {private $loop;öffentliche Funktion __construct(LoopInterface $loop) {$this->loop = $loop; }öffentliche Funktiongreet(string $name) {$this->loop->addTimer(1.0, function () use ($name) {echo 'Hello ' . $name . '!' . PHP_EOL; }); } }$greeter = new Greeter(Loop::get());$greeter->greet('Alice');$greeter->greet('Bob');
Weitere Informationen zu den verfügbaren Methoden finden Sie unter LoopInterface
.
Zusätzlich zum LoopInterface
stehen eine Reihe von Ereignisschleifenimplementierungen zur Verfügung.
Alle Ereignisschleifen unterstützen diese Funktionen:
Abfrage des Dateideskriptors
Einmalige Timer
Periodische Timer
Verzögerte Ausführung bei zukünftigem Schleifentick
Für die meisten Verbraucher dieses Pakets ist die zugrunde liegende Ereignisschleifenimplementierung ein Implementierungsdetail. Sie sollten die Loop
-Klasse verwenden, um automatisch eine neue Instanz zu erstellen.
Fortschrittlich! Wenn Sie explizit eine bestimmte Ereignisschleifenimplementierung benötigen, können Sie eine der folgenden Klassen manuell instanziieren. Beachten Sie, dass Sie möglicherweise zuerst die erforderlichen PHP-Erweiterungen für die jeweilige Ereignisschleifenimplementierung installieren müssen, da diese sonst bei der Erstellung eine BadMethodCallException
auslösen.
Eine stream_select()
-basierte Ereignisschleife.
Dies nutzt die Funktion stream_select()
und ist die einzige Implementierung, die sofort mit PHP funktioniert.
Diese Ereignisschleife funktioniert sofort auf jeder PHP-Version. Dies bedeutet, dass keine Installation erforderlich ist und diese Bibliothek auf allen Plattformen und unterstützten PHP-Versionen funktioniert. Dementsprechend verwendet die Loop
Klasse diese Ereignisschleife standardmäßig, wenn Sie keine der unten aufgeführten Ereignisschleifenerweiterungen installieren.
Unter der Haube führt es einen einfachen select
-Systemaufruf durch. Dieser Systemaufruf ist auf die maximale Dateideskriptornummer von FD_SETSIZE
(plattformabhängig, üblicherweise 1024) beschränkt und skaliert mit O(m)
(wobei m
die maximal übergebene Dateideskriptornummer ist). Dies bedeutet, dass bei der gleichzeitigen Verarbeitung von Tausenden von Streams möglicherweise Probleme auftreten und Sie in diesem Fall möglicherweise die Verwendung einer der unten aufgeführten alternativen Ereignisschleifenimplementierungen in Betracht ziehen sollten. Wenn Ihr Anwendungsfall zu den vielen häufigen Anwendungsfällen gehört, bei denen nur Dutzende oder einige Hundert Streams gleichzeitig verarbeitet werden müssen, ist die Leistung dieser Ereignisschleifenimplementierung wirklich gut.
Wenn Sie die Signalverarbeitung verwenden möchten (siehe auch addSignal()
unten), erfordert diese Ereignisschleifenimplementierung ext-pcntl
. Diese Erweiterung ist nur für Unix-ähnliche Plattformen verfügbar und unterstützt nicht Windows. Es wird häufig als Teil vieler PHP-Distributionen installiert. Wenn diese Erweiterung fehlt (oder Sie unter Windows ausführen), wird die Signalverarbeitung nicht unterstützt und löst stattdessen eine BadMethodCallException
aus.
Es ist bekannt, dass diese Ereignisschleife bei Verwendung einer Version vor PHP 7.3 auf der Uhrzeit der Wanduhr basiert, um zukünftige Timer zu planen, da eine monotone Zeitquelle erst ab PHP 7.3 ( hrtime()
) verfügbar ist. Während dies viele gängige Anwendungsfälle nicht betrifft, ist dies ein wichtiger Unterschied für Programme, die auf eine hohe Zeitgenauigkeit angewiesen sind oder auf Systemen, die diskontinuierlichen Zeitanpassungen (Zeitsprüngen) unterliegen. Das heißt, wenn Sie unter PHP < 7.3 einen Timer so planen, dass er in 30 Sekunden ausgelöst wird, und dann Ihre Systemzeit um 20 Sekunden nach vorne verschieben, kann der Timer in 10 Sekunden ausgelöst werden. Weitere Informationen finden Sie auch unter addTimer()
.
Eine ext-event
basierende Ereignisschleife.
Dabei wird die event
PECL-Erweiterung verwendet, die eine Schnittstelle zur libevent
-Bibliothek bereitstellt. libevent
selbst unterstützt eine Reihe systemspezifischer Backends (epoll, kqueue).
Es ist bekannt, dass diese Schleife mit PHP 7.1 bis PHP 8+ funktioniert.
Eine ext-ev
basierte Ereignisschleife.
Diese Schleife verwendet die ev
PECL-Erweiterung, die eine Schnittstelle zur libev
-Bibliothek bereitstellt. libev
selbst unterstützt eine Reihe systemspezifischer Backends (epoll, kqueue).
Es ist bekannt, dass diese Schleife mit PHP 7.1 bis PHP 8+ funktioniert.
Eine ext-uv
basierte Ereignisschleife.
Diese Schleife verwendet die uv
PECL-Erweiterung, die eine Schnittstelle zur libuv
-Bibliothek bereitstellt. libuv
selbst unterstützt eine Reihe systemspezifischer Backends (epoll, kqueue).
Es ist bekannt, dass diese Schleife mit PHP 7.1 bis PHP 8+ funktioniert.
Mit der Methode run(): void
kann die Ereignisschleife so lange ausgeführt werden, bis keine Aufgaben mehr ausgeführt werden müssen.
Für viele Anwendungen ist diese Methode der einzige direkt sichtbare Aufruf in der Ereignisschleife. Als Faustregel empfiehlt es sich normalerweise, alles an dieselbe Schleifeninstanz anzuhängen und die Schleife dann einmal am unteren Ende der Anwendung auszuführen.
$loop->run();
Diese Methode hält die Schleife am Laufen, bis keine weiteren Aufgaben mehr auszuführen sind. Mit anderen Worten: Diese Methode blockiert, bis der letzte Timer, Stream und/oder Signal entfernt wurde.
Ebenso muss unbedingt sichergestellt werden, dass die Anwendung diese Methode tatsächlich einmal aufruft. Das Hinzufügen von Listenern zur Schleife und deren tatsächliche Ausführung führt dazu, dass die Anwendung beendet wird, ohne tatsächlich auf einen der angehängten Listener zu warten.
Diese Methode DARF NICHT aufgerufen werden, während die Schleife bereits läuft. Diese Methode KANN mehr als einmal aufgerufen werden, nachdem sie explizit stop()
pediert wurde oder nachdem sie automatisch gestoppt wurde, weil sie zuvor nichts mehr zu tun hatte.
Die Methode stop(): void
kann verwendet werden, um eine laufende Ereignisschleife anzuweisen, zu stoppen.
Diese Methode gilt als fortgeschrittene Anwendung und sollte mit Vorsicht angewendet werden. Als Faustregel empfiehlt es sich meist, die Schleife erst dann automatisch stoppen zu lassen, wenn sie nichts mehr zu tun hat.
Diese Methode kann verwendet werden, um die Ereignisschleife explizit anzuweisen, zu stoppen:
$loop->addTimer(3.0, function () use ($loop) {$loop->stop(); });
Der Aufruf dieser Methode auf einer Schleifeninstanz, die derzeit nicht ausgeführt wird, oder auf einer Schleifeninstanz, die bereits gestoppt wurde, hat keine Auswirkung.
Die Methode addTimer(float $interval, callable $callback): TimerInterface
kann verwendet werden, um einen Rückruf in die Warteschlange einzureihen, der einmal nach dem angegebenen Intervall aufgerufen wird.
Der zweite Parameter MUSS eine Timer-Callback-Funktion sein, die die Timer-Instanz als einzigen Parameter akzeptiert. Wenn Sie die Timer-Instanz nicht in Ihrer Timer-Callback-Funktion verwenden, können Sie möglicherweise eine Funktion verwenden, die überhaupt keine Parameter hat.
Die Timer-Rückruffunktion DARF KEINE Exception
auslösen. Der Rückgabewert der Timer-Callback-Funktion wird ignoriert und hat keine Auswirkung. Aus Leistungsgründen wird daher empfohlen, keine übermäßigen Datenstrukturen zurückzugeben.
Diese Methode gibt eine Timer-Instanz zurück. Die gleiche Timer-Instanz wird auch wie oben beschrieben an die Timer-Callback-Funktion übergeben. Sie können cancelTimer
aufrufen, um einen ausstehenden Timer abzubrechen. Im Gegensatz zu addPeriodicTimer()
stellt diese Methode sicher, dass der Rückruf nur einmal nach dem angegebenen Intervall aufgerufen wird.
$loop->addTimer(0.8, function () {echo 'world!' . PHP_EOL; });$loop->addTimer(0.3, function () {echo 'hello '; });
Siehe auch Beispiel Nr. 1.
Wenn Sie auf beliebige Variablen innerhalb Ihrer Callback-Funktion zugreifen möchten, können Sie beliebige Daten wie folgt an einen Callback-Abschluss binden:
Funktion hallo($name, LoopInterface $loop) {$loop->addTimer(1.0, function () use ($name) {echo "hello $namen"; }); }hello('Tester', $loop);
Diese Schnittstelle erzwingt keine bestimmte Timer-Auflösung. Daher ist möglicherweise besondere Vorsicht geboten, wenn Sie sich auf eine sehr hohe Präzision mit einer Genauigkeit von Millisekunden oder darunter verlassen. Event-Loop-Implementierungen SOLLTEN nach bestem Wissen und Gewissen funktionieren und eine Genauigkeit von mindestens Millisekunden bieten, sofern nicht anders angegeben. Es ist bekannt, dass viele vorhandene Implementierungen von Ereignisschleifen eine Genauigkeit im Mikrosekundenbereich bieten, es wird jedoch im Allgemeinen nicht empfohlen, sich auf diese hohe Präzision zu verlassen.
Ebenso kann die Ausführungsreihenfolge von Timern, die zur gleichen Zeit ausgeführt werden sollen (im Rahmen ihrer möglichen Genauigkeit), nicht garantiert werden.
Diese Schnittstelle legt nahe, dass Ereignisschleifenimplementierungen, sofern verfügbar, eine monotone Zeitquelle verwenden SOLLTEN. Da eine monotone Zeitquelle standardmäßig erst ab PHP 7.3 verfügbar ist, können Ereignisschleifenimplementierungen möglicherweise auf die Verwendung der Wanduhrzeit zurückgreifen. Während dies viele häufige Anwendungsfälle nicht betrifft, ist dies ein wichtiger Unterschied für Programme, die auf eine hohe Zeitgenauigkeit angewiesen sind, oder für Systeme, die diskontinuierlichen Zeitanpassungen (Zeitsprüngen) unterliegen. Das heißt, wenn Sie einen Timer so planen, dass er in 30 Sekunden ausgelöst wird, und dann die Systemzeit um 20 Sekunden vorverstellen, SOLLTE der Timer immer noch in 30 Sekunden ausgelöst werden. Weitere Einzelheiten finden Sie unter Implementierungen von Ereignisschleifen.
Die Methode addPeriodicTimer(float $interval, callable $callback): TimerInterface
kann verwendet werden, um einen Rückruf in die Warteschlange einzureihen, der nach dem angegebenen Intervall wiederholt aufgerufen wird.
Der zweite Parameter MUSS eine Timer-Callback-Funktion sein, die die Timer-Instanz als einzigen Parameter akzeptiert. Wenn Sie die Timer-Instanz nicht in Ihrer Timer-Callback-Funktion verwenden, können Sie möglicherweise eine Funktion verwenden, die überhaupt keine Parameter hat.
Die Timer-Rückruffunktion DARF KEINE Exception
auslösen. Der Rückgabewert der Timer-Callback-Funktion wird ignoriert und hat keine Auswirkung. Aus Leistungsgründen wird daher empfohlen, keine übermäßigen Datenstrukturen zurückzugeben.
Diese Methode gibt eine Timer-Instanz zurück. Die gleiche Timer-Instanz wird auch wie oben beschrieben an die Timer-Callback-Funktion übergeben. Im Gegensatz zu addTimer()
stellt diese Methode sicher, dass der Rückruf nach dem angegebenen Intervall oder bis Sie cancelTimer
aufrufen unendlich oft aufgerufen wird.
$timer = $loop->addPeriodicTimer(0.1, function () {echo 'tick!' . PHP_EOL; });$loop->addTimer(1.0, function () use ($loop, $timer) {$loop->cancelTimer($timer);echo 'Done' . PHP_EOL; });
Siehe auch Beispiel #2.
Wenn Sie die Anzahl der Ausführungen begrenzen möchten, können Sie beliebige Daten wie folgt an einen Callback-Abschluss binden:
Funktion hallo($name, LoopInterface $loop) {$n = 3;$loop->addPeriodicTimer(1.0, function ($timer) use ($name, $loop, &$n) {if ($n > 0) { --$n;echo „Hallo $namen“; } else {$loop->cancelTimer($timer); } }); }hello('Tester', $loop);
Diese Schnittstelle erzwingt keine bestimmte Timer-Auflösung. Daher ist möglicherweise besondere Vorsicht geboten, wenn Sie auf eine sehr hohe Präzision mit einer Genauigkeit von Millisekunden oder weniger angewiesen sind. Event-Loop-Implementierungen SOLLTEN nach bestem Wissen und Gewissen funktionieren und eine Genauigkeit von mindestens Millisekunden bieten, sofern nicht anders angegeben. Es ist bekannt, dass viele vorhandene Ereignisschleifenimplementierungen eine Genauigkeit im Mikrosekundenbereich bieten, es wird jedoch im Allgemeinen nicht empfohlen, sich auf diese hohe Präzision zu verlassen.
Ebenso kann die Ausführungsreihenfolge von Timern, die zur gleichen Zeit ausgeführt werden sollen (im Rahmen ihrer möglichen Genauigkeit), nicht garantiert werden.
Diese Schnittstelle legt nahe, dass Ereignisschleifenimplementierungen, sofern verfügbar, eine monotone Zeitquelle verwenden SOLLTEN. Da eine monotone Zeitquelle standardmäßig erst ab PHP 7.3 verfügbar ist, können Ereignisschleifenimplementierungen möglicherweise auf die Verwendung der Wanduhrzeit zurückgreifen. Während dies viele gängige Anwendungsfälle nicht betrifft, ist dies ein wichtiger Unterschied für Programme, die auf eine hohe Zeitgenauigkeit angewiesen sind, oder für Systeme, die diskontinuierlichen Zeitanpassungen (Zeitsprüngen) unterliegen. Das heißt, wenn Sie einen Timer so planen, dass er in 30 Sekunden ausgelöst wird, und dann die Systemzeit um 20 Sekunden vorverstellen, SOLLTE der Timer immer noch in 30 Sekunden ausgelöst werden. Weitere Einzelheiten finden Sie unter Implementierungen von Ereignisschleifen.
Darüber hinaus kann es bei periodischen Timern aufgrund der Neuplanung nach jedem Aufruf zu einer Timerabweichung kommen. Daher ist es im Allgemeinen nicht empfehlenswert, sich bei hochpräzisen Intervallen mit einer Genauigkeit im Millisekundenbereich oder darunter darauf zu verlassen.
Mit der Methode cancelTimer(TimerInterface $timer): void
kann ein ausstehender Timer abgebrochen werden.
Siehe auch addPeriodicTimer()
und Beispiel #2.
Der Aufruf dieser Methode für eine Timer-Instanz, die dieser Schleifeninstanz nicht hinzugefügt wurde, oder für einen Timer, der bereits abgebrochen wurde, hat keine Auswirkung.
Die Methode futureTick(callable $listener): void
kann verwendet werden, um einen Rückruf zu planen, der bei einem zukünftigen Tick der Ereignisschleife aufgerufen wird.
Dies funktioniert sehr ähnlich wie Timer mit einem Intervall von null Sekunden, erfordert jedoch nicht den Aufwand für die Planung einer Timer-Warteschlange.
Die Tick-Callback-Funktion MUSS in der Lage sein, Null-Parameter zu akzeptieren.
Die Tick-Callback-Funktion DARF KEINE Exception
auslösen. Der Rückgabewert der Tick-Callback-Funktion wird ignoriert und hat keine Auswirkung. Aus Leistungsgründen wird daher empfohlen, keine übermäßigen Datenstrukturen zurückzugeben.
Wenn Sie auf beliebige Variablen innerhalb Ihrer Callback-Funktion zugreifen möchten, können Sie beliebige Daten wie folgt an einen Callback-Abschluss binden:
Funktion hallo($name, LoopInterface $loop) {$loop->futureTick(function () use ($name) {echo "hello $namen"; }); }hello('Tester', $loop);
Im Gegensatz zu Timern werden Tick-Callbacks garantiert in der Reihenfolge ausgeführt, in der sie in die Warteschlange gestellt werden. Außerdem gibt es keine Möglichkeit, diesen Vorgang abzubrechen, sobald ein Rückruf in die Warteschlange gestellt wird.
Dies wird häufig verwendet, um größere Aufgaben in kleinere Schritte zu unterteilen (eine Form des kooperativen Multitasking).
$loop->futureTick(function () {echo 'b'; });$loop->futureTick(function () {echo 'c'; });echo 'a';
Siehe auch Beispiel #3.
Die Methode addSignal(int $signal, callable $listener): void
kann verwendet werden, um einen Listener zu registrieren, der benachrichtigt wird, wenn ein Signal von diesem Prozess abgefangen wurde.
Dies ist nützlich, um Benutzer-Interrupt-Signale oder Shutdown-Signale von Tools wie supervisor
oder systemd
abzufangen.
Der zweite Parameter MUSS eine Listener-Callback-Funktion sein, die das Signal als einzigen Parameter akzeptiert. Wenn Sie das Signal nicht in Ihrer Listener-Callback-Funktion verwenden, können Sie möglicherweise eine Funktion verwenden, die überhaupt keine Parameter hat.
Die Listener-Rückruffunktion DARF KEINE Exception
auslösen. Der Rückgabewert der Listener-Rückruffunktion wird ignoriert und hat keine Auswirkung. Aus Leistungsgründen wird daher empfohlen, keine übermäßigen Datenstrukturen zurückzugeben.
$loop->addSignal(SIGINT, function (int $signal) {echo 'Interrupt-Signal des Benutzers abgefangen' . PHP_EOL; });
Siehe auch Beispiel Nr. 4.
Die Signalisierung ist nur auf Unix-ähnlichen Plattformen verfügbar. Windows wird aufgrund von Einschränkungen des Betriebssystems nicht unterstützt. Diese Methode kann eine BadMethodCallException
auslösen, wenn Signale auf dieser Plattform nicht unterstützt werden, beispielsweise wenn erforderliche Erweiterungen fehlen.
Hinweis: Ein Listener kann nur einmal zum gleichen Signal hinzugefügt werden. Alle Versuche, ihn mehr als einmal hinzuzufügen, werden ignoriert.
Die Methode removeSignal(int $signal, callable $listener): void
kann verwendet werden, um einen zuvor hinzugefügten Signal-Listener zu entfernen.
$loop->removeSignal(SIGINT, $listener);
Alle Versuche, nicht registrierte Listener zu entfernen, werden ignoriert.
Fortschrittlich! Beachten Sie, dass diese Low-Level-API als erweiterte Verwendung gilt. In den meisten Anwendungsfällen sollte wahrscheinlich stattdessen die lesbare Stream-API auf höherer Ebene verwendet werden.
Mit der Methode addReadStream(resource $stream, callable $callback): void
kann ein Listener registriert werden, der benachrichtigt wird, wenn ein Stream zum Lesen bereit ist.
Der erste Parameter MUSS eine gültige Stream-Ressource sein, die die Überprüfung unterstützt, ob sie von dieser Schleifenimplementierung zum Lesen bereit ist. Eine einzelne Stream-Ressource DARF NICHT mehr als einmal hinzugefügt werden. Rufen Sie stattdessen entweder zuerst removeReadStream()
auf oder reagieren Sie mit einem einzelnen Listener auf dieses Ereignis und senden Sie es dann von diesem Listener aus. Diese Methode kann eine Exception
auslösen, wenn der angegebene Ressourcentyp von dieser Schleifenimplementierung nicht unterstützt wird.
Der zweite Parameter MUSS eine Listener-Callback-Funktion sein, die die Stream-Ressource als einzigen Parameter akzeptiert. Wenn Sie die Stream-Ressource nicht in Ihrer Listener-Callback-Funktion verwenden, können Sie möglicherweise eine Funktion verwenden, die überhaupt keine Parameter hat.
Die Listener-Rückruffunktion DARF KEINE Exception
auslösen. Der Rückgabewert der Listener-Rückruffunktion wird ignoriert und hat keine Auswirkung. Aus Leistungsgründen wird daher empfohlen, keine übermäßigen Datenstrukturen zurückzugeben.
Wenn Sie auf beliebige Variablen innerhalb Ihrer Callback-Funktion zugreifen möchten, können Sie beliebige Daten wie folgt an einen Callback-Abschluss binden:
$loop->addReadStream($stream, function ($stream) use ($name) {echo $name . ' sagte: ' . fread($stream); });
Siehe auch Beispiel Nr. 11.
Sie können removeReadStream()
aufrufen, um den Leseereignis-Listener für diesen Stream zu entfernen.
Die Ausführungsreihenfolge der Listener kann nicht garantiert werden, wenn mehrere Streams gleichzeitig bereit werden.
Es ist bekannt, dass einige Ereignisschleifenimplementierungen den Listener nur auslösen, wenn der Stream lesbar wird (flankenausgelöst), und möglicherweise nicht auslöst, wenn der Stream bereits von Anfang an lesbar war. Dies bedeutet auch, dass ein Stream möglicherweise nicht als lesbar erkannt wird, wenn sich noch Daten in den internen Stream-Puffer von PHP befinden. Daher wird empfohlen, stream_set_read_buffer($stream, 0);
um in diesem Fall den internen Lesepuffer von PHP zu deaktivieren.
Fortschrittlich! Beachten Sie, dass diese Low-Level-API als erweiterte Verwendung gilt. In den meisten Anwendungsfällen sollte wahrscheinlich stattdessen die übergeordnete beschreibbare Stream-API verwendet werden.
Mit der Methode addWriteStream(resource $stream, callable $callback): void
kann ein Listener registriert werden, der benachrichtigt wird, wenn ein Stream zum Schreiben bereit ist.
Der erste Parameter MUSS eine gültige Stream-Ressource sein, die die Prüfung unterstützt, ob sie durch diese Schleifenimplementierung zum Schreiben bereit ist. Eine einzelne Stream-Ressource DARF NICHT mehr als einmal hinzugefügt werden. Rufen Sie stattdessen entweder zuerst removeWriteStream()
auf oder reagieren Sie mit einem einzelnen Listener auf dieses Ereignis und senden Sie es dann von diesem Listener aus. Diese Methode kann eine Exception
auslösen, wenn der angegebene Ressourcentyp von dieser Schleifenimplementierung nicht unterstützt wird.
Der zweite Parameter MUSS eine Listener-Callback-Funktion sein, die die Stream-Ressource als einzigen Parameter akzeptiert. Wenn Sie die Stream-Ressource nicht in Ihrer Listener-Callback-Funktion verwenden, können Sie möglicherweise eine Funktion verwenden, die überhaupt keine Parameter hat.
Die Listener-Rückruffunktion DARF KEINE Exception
auslösen. Der Rückgabewert der Listener-Rückruffunktion wird ignoriert und hat keine Auswirkung. Aus Leistungsgründen wird daher empfohlen, keine übermäßigen Datenstrukturen zurückzugeben.
Wenn Sie auf beliebige Variablen innerhalb Ihrer Callback-Funktion zugreifen möchten, können Sie beliebige Daten wie folgt an einen Callback-Abschluss binden:
$loop->addWriteStream($stream, function ($stream) use ($name) {fwrite($stream, 'Hello ' . $name); });
Siehe auch Beispiel #12.
Sie können removeWriteStream()
aufrufen, um den Schreibereignis-Listener für diesen Stream zu entfernen.
Die Ausführungsreihenfolge der Listener kann nicht garantiert werden, wenn mehrere Streams gleichzeitig bereit werden.
Die Methode removeReadStream(resource $stream): void
kann verwendet werden, um den Leseereignis-Listener für den angegebenen Stream zu entfernen.
Das Entfernen eines Streams aus der Schleife, der bereits entfernt wurde, oder der Versuch, einen Stream zu entfernen, der nie hinzugefügt wurde oder ungültig ist, hat keine Auswirkung.
Die Methode removeWriteStream(resource $stream): void
kann verwendet werden, um den Schreibereignis-Listener für den angegebenen Stream zu entfernen.
Das Entfernen eines Streams aus der Schleife, der bereits entfernt wurde, oder der Versuch, einen Stream zu entfernen, der nie hinzugefügt wurde oder ungültig ist, hat keine Auswirkung.
Die empfohlene Methode zur Installation dieser Bibliothek ist Composer. Neu bei Composer?
Nach der Veröffentlichung wird dieses Projekt SemVer folgen. Im Moment wird dadurch die neueste Entwicklungsversion installiert:
Komponist benötigt React/Event-Loop:^3@dev
Einzelheiten zu Versionsaktualisierungen finden Sie auch im CHANGELOG.
Dieses Projekt zielt darauf ab, auf jeder Plattform ausgeführt zu werden, erfordert daher keine PHP-Erweiterungen und unterstützt die Ausführung auf PHP 7.1 bis zum aktuellen PHP 8+. Es wird dringend empfohlen, für dieses Projekt die neueste unterstützte PHP-Version zu verwenden .
Die Installation einer der Event-Loop-Erweiterungen wird empfohlen, ist jedoch völlig optional. Weitere Einzelheiten finden Sie unter Implementierungen von Ereignisschleifen.
Um die Testsuite auszuführen, müssen Sie zunächst dieses Repo klonen und dann alle Abhängigkeiten über Composer installieren:
Composer installieren
Um die Testsuite auszuführen, gehen Sie zum Projektstammverzeichnis und führen Sie Folgendes aus:
Vendor/bin/phpunit
MIT, siehe LICENSE-Datei.
Weitere Informationen zur Verwendung von Streams in realen Anwendungen finden Sie in unserer Stream-Komponente.
Eine Liste der Pakete, die EventLoop in realen Anwendungen verwenden, finden Sie im Wiki unserer Benutzer und in den Packagist-Abhängigen.