Signatur
Beschreibung
EvIo ist ein Watcher der PECL-Erweiterung ev und benachrichtigt die Anwendung, sobald ein Dateideskriptor oder Socket zum Lesen (Ev::READ) oder Schreiben (Ev::WRITE) bereit ist. Dadurch lassen sich nicht-blockierende I/O-Operationen effizient umsetzen, ohne dauerhaft auf Daten pollen zu müssen.
Typische Einsatzgebiete sind asynchrone Netzwerkserver, Event-getriebene Clients oder generell jede Situation, in der mehrere Verbindungen gleichzeitig ohne Threads verwaltet werden sollen. EvIo arbeitet dabei eng mit der EvLoop-Instanz oder der globalen Standard-Loop zusammen.
Der Watcher wird mit einem Dateideskriptor (z. B. einer Stream-Ressource, die über stream_socket_server() oder socket_create() erzeugt wurde), einem Ereignis-Bitfeld (Ev::READ, Ev::WRITE oder deren OR-Verknüpfung) und einem Callback instanziiert. Sobald das überwachte Ereignis eintritt, ruft die Ereignisschleife den Callback auf.
Wichtig: EvIo-Watcher reagieren auf Bereitschaft (readiness), nicht auf Abschluss; der eigentliche Lese- bzw. Schreibvorgang muss im Callback selbst durchgeführt werden. Für korrekte Funktion sollte der Deskriptor auf nicht-blockierend (stream_set_blocking($fd, false)) gesetzt sein.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $fd Pflicht | mixed | Der zu überwachende Dateideskriptor: eine PHP-Stream-Ressource, eine Socket-Ressource oder eine ganze Zahl (roher Dateideskriptor). Muss für nicht-blockierende Nutzung vorbereitet sein. | |
| $events Pflicht | int | Bitmaske der zu überwachenden Ereignisse: Ev::READ, Ev::WRITE oder Ev::READ | Ev::WRITE. |
|
| $callback Pflicht | callable | Callback-Funktion, die aufgerufen wird, wenn das Ereignis eintritt. Signatur: function(EvIo $watcher, int $revents): void. |
|
| $data | mixed | null | Beliebige Benutzerdaten, die dem Watcher zugeordnet und über $watcher->data im Callback abrufbar sind. |
| $priority | int | 0 | Priorität des Watchers. Höhere Werte bedeuten höhere Priorität. Erlaubter Bereich: Ev::MINPRI bis Ev::MAXPRI. |
Beispiele
Nicht-blockierender TCP-Server mit EvIo
<?php
// Einfacher Echo-Server mit ev-Ereignisschleife
$server = stream_socket_server('tcp://127.0.0.1:9000', $errno, $errstr);
if (!$server) {
die("Server konnte nicht gestartet werden: $errstr ($errno)\n");
}
stream_set_blocking($server, false);
// Watcher für eingehende Verbindungen
$acceptWatcher = new EvIo($server, Ev::READ, function ($watcher, $revents) use ($server) {
$client = stream_socket_accept($server, 0);
if (!$client) {
return;
}
stream_set_blocking($client, false);
// Watcher für Lesevorgänge auf dem Client-Socket
$readWatcher = new EvIo($client, Ev::READ, function ($w, $rev) use ($client, &$readWatcher) {
$data = fread($client, 1024);
if ($data === '' || $data === false) {
$readWatcher->stop();
fclose($client);
return;
}
// Echo zurück
fwrite($client, $data);
});
});
echo "Server lauscht auf 127.0.0.1:9000 ...\n";
Ev::run();
EvIo zum Überwachen von STDIN
<?php
// Liest Zeilen von STDIN asynchron, bis 'quit' eingegeben wird
stream_set_blocking(STDIN, false);
$stdinWatcher = new EvIo(STDIN, Ev::READ, function ($watcher, $revents) {
$line = rtrim(fgets(STDIN));
if ($line === false || $line === '') {
return;
}
echo "Eingabe empfangen: $line\n";
if ($line === 'quit') {
$watcher->stop();
Ev::stop();
}
});
Ev::run();
// Wichtig · Fallstricke
Nicht-blockierender Modus: Der überwachte Dateideskriptor sollte unbedingt auf nicht-blockierend gesetzt werden (stream_set_blocking($fd, false)), da EvIo nur die Bereitschaft signalisiert, nicht aber garantiert, dass eine vollständige Datenmenge verfügbar ist.
Lebensdauer des Watchers: Solange eine EvIo-Instanz aktiv ist (d. h. nicht gestoppt oder zerstört wurde), hält sie intern eine Referenz auf den Dateideskriptor. Ein explizites $watcher->stop() ist empfehlenswert, bevor der zugehörige Deskriptor geschlossen wird, um Ressourcenlecks zu vermeiden.
Plattformabhängigkeit: Unter Windows sind EvIo-Watcher nur mit Sockets nutzbar; reguläre Datei-Handles werden dort von libev nicht unterstützt.
Verfügbarkeit: EvIo setzt die PECL-Erweiterung ev voraus, die nicht zum PHP-Kern gehört und separat installiert werden muss (pecl install ev).