Signatur
Beschreibung
Die Klasse Event ist Teil der PECL-Event-Erweiterung und bildet die Kernabstraktion der libevent-Bibliothek. Ein Objekt dieser Klasse repräsentiert ein einzelnes Ereignis, das auf einem Dateideskriptor (Socket, Pipe, reguläre Datei), einem Timer oder einem Betriebssystem-Signal basiert. Sobald das Ereignis eintritt, wird eine registrierte Callback-Funktion aufgerufen.
Ereignisse können pegelgesteuert (level-triggered) oder flankengesteuert (edge-triggered, Flag Event::ET) sein. Bei pegelgesteuerten Ereignissen wird der Callback so lange wiederholt aufgerufen, wie der Zustand (z. B. Daten im Puffer) anhält; bei flankengesteuerten Ereignissen nur dann, wenn ein Zustandswechsel eintritt. Flankengesteuerte Modi sind effizienter, erfordern aber sorgfältigeres Puffermanagement.
Ein Event-Objekt muss einer EventBase-Instanz zugeordnet und explizit aktiviert werden (Event::add()), bevor es überwacht wird. Typische Einsatzgebiete sind hochperformante Netzwerkserver, asynchrone HTTP-Clients, Datenbankverbindungspools und jede Anwendung, die viele gleichzeitige I/O-Operationen ohne Threads verwalten muss.
- Lese-/Schreibereignisse: Reagieren, sobald ein Deskriptor lesbar oder schreibbar ist (
Event::READ,Event::WRITE). - Timer-Ereignisse: Einmalige oder wiederkehrende Zeitgeber ohne Dateideskriptor.
- Signal-Ereignisse: Asynchrones Abfangen von POSIX-Signalen (
Event::SIGNAL).
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $base Pflicht | EventBase | Die EventBase-Instanz, der dieses Ereignis zugeordnet wird. Alle Ereignisse einer Anwendung teilen sich typischerweise eine gemeinsame Basis. |
|
| $fd Pflicht | mixed | Der zu überwachende Dateideskriptor oder Socket (PHP-Resource), oder -1 für Timer-Ereignisse bzw. ein Signal-Deskriptor bei Signal-Ereignissen. |
|
| $what Pflicht | int | Bitmaske der Ereignisflags. Mögliche Werte: Event::READ, Event::WRITE, Event::SIGNAL, Event::TIMEOUT, Event::PERSIST (wiederholt auslösen), Event::ET (flankengesteuert). |
|
| $cb Pflicht | callable | Die Callback-Funktion, die aufgerufen wird, wenn das Ereignis eintritt. Signatur: function(mixed $fd, int $what, mixed $arg): void. |
|
| $arg | mixed | null | Optionaler benutzerdefinierter Wert, der unverändert als drittes Argument an den Callback übergeben wird (z. B. Kontext-Objekt oder Verbindungsstruktur). |
Rückgabewert
Beispiele
Einfacher TCP-Echo-Server mit Event::READ und Event::PERSIST
<?php
// Voraussetzung: PECL-Erweiterung 'event' installiert
$base = new EventBase();
$server = stream_socket_server('tcp://0.0.0.0:8080', $errno, $errstr);
stream_set_blocking($server, false);
// Akzeptiere neue Verbindungen
$acceptEvent = new Event($base, $server, Event::READ | Event::PERSIST, function ($fd) use ($base) {
$conn = stream_socket_accept($fd);
if (!$conn) {
return;
}
stream_set_blocking($conn, false);
// Für jede Verbindung ein eigenes Lese-Ereignis erzeugen
$readEvent = new Event($base, $conn, Event::READ | Event::PERSIST, function ($fd, $what, $ev) {
$data = fread($fd, 4096);
if ($data === false || $data === '') {
$ev->del();
fclose($fd);
return;
}
fwrite($fd, $data); // Echo zurückschicken
});
$readEvent->add();
// Referenz halten, damit GC das Objekt nicht zerstört
$GLOBALS['events'][] = $readEvent;
});
$acceptEvent->add();
echo "Echo-Server lauscht auf Port 8080...\n";
$base->loop();
Periodischer Timer mit Event::TIMEOUT und Event::PERSIST
<?php
$base = new EventBase();
$counter = 0;
// Timer-Ereignis: kein Dateideskriptor (-1), nur TIMEOUT | PERSIST
$timer = new Event($base, -1, Event::TIMEOUT | Event::PERSIST, function () use (&$counter, &$timer, $base) {
$counter++;
echo "Tick #{$counter} um " . date('H:i:s') . "\n";
if ($counter >= 3) {
$timer->del(); // Nach 3 Ticks stoppen
$base->exit(); // Event-Loop beenden
}
});
// Alle 1000 ms (1 Sekunde) auslösen
$timer->add(1.0);
$base->loop();
echo "Timer beendet.\n";
// Wichtig · Fallstricke
Lebenszyklus: Ein Event-Objekt bleibt nur so lange aktiv, wie eine PHP-Variable eine Referenz darauf hält. Wird das Objekt vom Garbage Collector freigegeben, wird das Ereignis automatisch deregistriert – ein häufiger Fehler ist, das Objekt in einer lokalen Variable zu erzeugen und dann aus dem Scope zu verlieren.
Nicht-blockierender Modus: Alle Dateideskriptoren, die mit Event überwacht werden, müssen in den nicht-blockierenden Modus versetzt werden (z. B. via stream_set_blocking($fd, false)), da sonst der gesamte Event-Loop blockiert.
Flankengesteuert (Event::ET): Wird nur von bestimmten Backends (epoll, kqueue) unterstützt. Im flankengesteuerten Modus muss der Callback den Puffer vollständig leeren, da sonst keine weiteren Ereignisse ausgelöst werden.
Signale: Signal-Ereignisse sind nur auf POSIX-Systemen verfügbar und sollten nicht mit PHPs eingebautem pcntl_signal() kombiniert werden, da es zu Konflikten kommen kann.