Bucle de eventos del reactor central de ReactPHP que las bibliotecas pueden usar para E/S por eventos.
Versión de desarrollo: esta rama contiene el código para la próxima versión v3. Para obtener el código de la versión estable v1 actual, consulte la rama
1.x
La próxima versión v3 será el camino a seguir para este paquete. Sin embargo, seguiremos admitiendo activamente la versión 1 para aquellos que aún no tengan la última versión. Consulte también las instrucciones de instalación para obtener más detalles.
Para que las bibliotecas basadas en asíncrono sean interoperables, deben utilizar el mismo bucle de eventos. Este componente proporciona una LoopInterface
común a la que puede acceder cualquier biblioteca. Esto permite que se utilicen en el mismo bucle, con una única llamada run()
controlada por el usuario.
Tabla de contenido
Ejemplo de inicio rápido
Uso
correr()
detener()
agregar temporizador()
agregarTemporizadorPeriódico()
cancelar temporizador()
tic futuro()
agregarSeñal()
eliminarSeñal()
agregarReadStream()
agregarWriteStream()
eliminarReadStream()
eliminarWriteStream()
StreamSelectLoop
ExtEventLoop
ExtEvLoop
ExtUvLoop
Métodos de bucle
Ejecución automática de bucle
conseguir()
Bucle
Implementaciones de bucle
Interfaz de bucle
Instalar
Pruebas
Licencia
Más
Aquí hay un servidor HTTP asíncrono creado solo con el bucle de eventos.
<?phpuse ReactEventLoopLoop;requiere __DIR__ . '/vendor/autoload.php';$servidor = stream_socket_server('tcp://127.0.0.1:8080');stream_set_blocking($servidor, false); Bucle::addReadStream($servidor, función ($servidor) {$conn = stream_socket_accept($servidor);$datos = "HTTP/1.1 200 OKrnContent-Length: 3rnrnHin"; Bucle::addWriteStream($conn, función ($conn) use (&$datos) {$escrito = fwrite($conn, $datos);if ($escrito === strlen($datos)) {fclose($conn) ); Bucle::removeWriteStream($conn); } else {$datos = substr($datos, $escrito); } }); }); Loop::addPeriodicTimer(5, function () {$memory = Memory_get_usage() / 1024;$formatted = number_format($memory, 3).'K';echo "Uso actual de memoria: {$formatted}n"; });
Vea también los ejemplos.
Las aplicaciones típicas usarían la clase Loop
para usar el bucle de eventos predeterminado como este:
use ReactEventLoopLoop;$timer = Loop::addPeriodicTimer(0.1, function () {echo 'Tick' . PHP_EOL; }); Bucle::addTimer(1.0, función () uso ($temporizador) { Bucle::cancelTimer($timer);echo 'Listo'. PHP_EOL; });
Como alternativa, también puedes crear explícitamente una instancia de bucle de eventos al principio, reutilizarla en todo tu programa y finalmente ejecutarla al final del programa de esta manera:
$loop = ReactEventLoopLoop::get();$timer = $loop->addPeriodicTimer(0.1, function () {echo 'Tick' . PHP_EOL; });$loop->addTimer(1.0, función () use ($loop, $timer) {$loop->cancelTimer($timer);echo 'Listo' . PHP_EOL; });$bucle->ejecutar();
Mientras que el primero es más conciso, el segundo es más explícito. En ambos casos, el programa realizaría exactamente los mismos pasos.
La instancia del bucle de eventos se crea al comienzo del programa. Esto se hace implícitamente la primera vez que llamas a la clase Loop
(o al crear una instancia manual de cualquiera de las implementaciones del bucle).
El bucle de eventos se usa directamente o se pasa como una instancia al código de la biblioteca y la aplicación. En este ejemplo, se registra un temporizador periódico con el bucle de eventos que simplemente genera Tick
cada fracción de segundo hasta que otro temporizador detiene el temporizador periódico después de un segundo.
El bucle de eventos se ejecuta al final del programa. Esto se hace automáticamente cuando se usa la clase Loop
o explícitamente con una única llamada run()
al final del programa.
A partir de v1.2.0
, recomendamos encarecidamente utilizar la clase Loop
. Las instrucciones de bucle explícitas siguen siendo válidas y pueden resultar útiles en algunas aplicaciones, especialmente durante un período de transición hacia un estilo más conciso.
La clase Loop
existe como un conveniente acceso global para el bucle de eventos.
La clase Loop
proporciona todos los métodos que existen en LoopInterface
como métodos estáticos:
correr()
detener()
agregar temporizador()
agregarTemporizadorPeriódico()
cancelar temporizador()
tic futuro()
agregarSeñal()
eliminarSeñal()
agregarReadStream()
agregarWriteStream()
eliminarReadStream()
eliminarWriteStream()
Si está trabajando con el bucle de eventos en el código de su aplicación, a menudo es más fácil interactuar directamente con los métodos estáticos definidos en la clase Loop
de esta manera:
use ReactEventLoopLoop;$timer = Loop::addPeriodicTimer(0.1, function () {echo 'Tick' . PHP_EOL; }); Bucle::addTimer(1.0, función () uso ($temporizador) { Bucle::cancelTimer($timer);echo 'Listo'. PHP_EOL; });
Por otro lado, si está familiarizado con la programación orientada a objetos (OOP) y la inyección de dependencia (DI), es posible que desee inyectar una instancia de bucle de eventos e invocar métodos de instancia en LoopInterface
de esta manera:
utilizar ReactEventLoopLoop; utilizar ReactEventLoopLoopInterface; clase Greeter {privado $bucle;función pública __construct(LoopInterface $bucle) {$este->bucle = $bucle; }saludo de función pública (cadena $ nombre) {$this->loop->addTimer(1.0, función () use ($nombre) {echo 'Hola' . $nombre . '!' . PHP_EOL; }); } }$saludo = new Saludo(Loop::get());$saludo->saludo('Alice');$saludo->saludo('Bob');
Cada llamada al método estático se reenviará tal cual a la instancia del bucle de eventos subyacente mediante la llamada Loop::get()
internamente. Consulte LoopInterface
para obtener más detalles sobre los métodos disponibles.
Cuando se utiliza la clase Loop
, ejecutará automáticamente el bucle al final del programa. Esto significa que el siguiente ejemplo programará un temporizador y ejecutará automáticamente el programa hasta que se active el evento del temporizador:
utilizar ReactEventLoopLoop; Bucle::addTimer(1.0, función () {echo 'Hola' . PHP_EOL; });
A partir de v1.2.0
, recomendamos encarecidamente utilizar la clase Loop
de esta manera y omitir cualquier llamada run()
explícita. Por razones de BC, el método run()
explícito sigue siendo válido y puede seguir siendo útil en algunas aplicaciones, especialmente durante un período de transición hacia un estilo más conciso.
Si no desea que el Loop
se ejecute automáticamente, puede run()
o stop()
. Esto puede resultar útil si utiliza un controlador de excepciones global como este:
utilizar ReactEventLoopLoop; Loop::addTimer(10.0, function () {echo 'Nunca sucede'; });set_exception_handler(function (Throwable $e) {echo 'Error: ' . $e->getMessage() . PHP_EOL; Bucle::detener(); });lanzar nueva RuntimeException('Demo');
El método get(): LoopInterface
se puede utilizar para obtener la instancia del bucle de eventos actualmente activa.
Este método siempre devolverá la misma instancia de bucle de eventos durante toda la vida útil de su aplicación.
use ReactEventLoopLoop;use ReactEventLoopLoopInterface;$loop = Loop::get();assert($loop instancia de LoopInterface);assert($loop === Loop::get());
Esto es particularmente útil si utiliza programación orientada a objetos (OOP) e inyección de dependencia (DI). En este caso, es posible que desee inyectar una instancia de bucle de eventos e invocar métodos de instancia en LoopInterface
de esta manera:
utilizar ReactEventLoopLoop; utilizar ReactEventLoopLoopInterface; clase Greeter {privado $bucle;función pública __construct(LoopInterface $bucle) {$este->bucle = $bucle; }saludo de función pública (cadena $ nombre) {$this->loop->addTimer(1.0, función () use ($nombre) {echo 'Hola' . $nombre . '!' . PHP_EOL; }); } }$saludo = new Saludo(Loop::get());$saludo->saludo('Alice');$saludo->saludo('Bob');
Consulte LoopInterface
para obtener más detalles sobre los métodos disponibles.
Además de LoopInterface
, se proporcionan varias implementaciones de bucles de eventos.
Todos los bucles de eventos admiten estas características:
Sondeo de descriptores de archivos
Temporizadores únicos
Temporizadores periódicos
Ejecución diferida en un ciclo futuro
Para la mayoría de los consumidores de este paquete, la implementación del bucle de eventos subyacente es un detalle de implementación. Debes usar la clase Loop
para crear automáticamente una nueva instancia.
¡Avanzado! Si necesita explícitamente una determinada implementación de bucle de eventos, puede crear manualmente una instancia de una de las siguientes clases. Tenga en cuenta que es posible que primero deba instalar las extensiones PHP requeridas para la implementación del bucle de eventos respectivo o generarán una BadMethodCallException
al crear.
Un bucle de eventos basado en stream_select()
.
Esto utiliza la función stream_select()
y es la única implementación que funciona de forma inmediata con PHP.
Este bucle de eventos funciona de forma inmediata en cualquier versión de PHP. Esto significa que no se requiere instalación y esta biblioteca funciona en todas las plataformas y versiones de PHP compatibles. En consecuencia, la clase Loop
utilizará este bucle de eventos de forma predeterminada si no instala ninguna de las extensiones de bucle de eventos que se enumeran a continuación.
Debajo del capó, realiza una simple llamada al sistema select
. Esta llamada al sistema está limitada al número máximo de descriptor de archivo de FD_SETSIZE
(dependiente de la plataforma, comúnmente 1024) y escala con O(m)
(siendo m
el número máximo de descriptor de archivo pasado). Esto significa que puede tener problemas al manejar miles de transmisiones simultáneamente y es posible que desee considerar el uso de una de las implementaciones de bucle de eventos alternativas que se enumeran a continuación en este caso. Si su caso de uso se encuentra entre los muchos casos de uso comunes que implican manejar solo docenas o unos pocos cientos de transmisiones a la vez, entonces esta implementación de bucle de eventos funciona realmente bien.
Si desea utilizar el manejo de señales (consulte también addSignal()
a continuación), esta implementación de bucle de eventos requiere ext-pcntl
. Esta extensión sólo está disponible para plataformas tipo Unix y no es compatible con Windows. Comúnmente se instala como parte de muchas distribuciones PHP. Si falta esta extensión (o está ejecutando Windows), el manejo de señales no es compatible y en su lugar genera una excepción BadMethodCallException
.
Se sabe que este bucle de eventos depende del tiempo del reloj de pared para programar temporizadores futuros cuando se usa cualquier versión anterior a PHP 7.3, porque una fuente de tiempo monótona solo está disponible a partir de PHP 7.3 ( hrtime()
). Si bien esto no afecta a muchos casos de uso comunes, es una distinción importante para programas que dependen de una alta precisión temporal o de sistemas sujetos a ajustes de tiempo discontinuos (saltos de tiempo). Esto significa que si programa un temporizador para que se active en 30 segundos en PHP < 7.3 y luego ajusta el tiempo de su sistema hacia adelante en 20 segundos, el temporizador puede activarse en 10 segundos. Consulte también addTimer()
para obtener más detalles.
Un bucle de eventos basado en ext-event
.
Esto utiliza la extensión PECL event
, que proporciona una interfaz para la biblioteca libevent
. El propio libevent
admite varios backends específicos del sistema (epoll, kqueue).
Se sabe que este bucle funciona desde PHP 7.1 hasta PHP 8+.
Un bucle de eventos basado en ext-ev
.
Este bucle utiliza la extensión ev
PECL, que proporciona una interfaz para la biblioteca libev
. El propio libev
admite varios backends específicos del sistema (epoll, kqueue).
Se sabe que este bucle funciona desde PHP 7.1 hasta PHP 8+.
Un bucle de eventos basado en ext-uv
.
Este bucle utiliza la extensión uv
PECL, que proporciona una interfaz para la biblioteca libuv
. El propio libuv
admite varios backends específicos del sistema (epoll, kqueue).
Se sabe que este bucle funciona desde PHP 7.1 hasta PHP 8+.
El método run(): void
se puede utilizar para ejecutar el bucle de eventos hasta que no haya más tareas que realizar.
Para muchas aplicaciones, este método es la única invocación directamente visible en el bucle de eventos. Como regla general, normalmente se recomienda adjuntar todo a la misma instancia de bucle y luego ejecutar el bucle una vez en el extremo inferior de la aplicación.
$bucle->ejecutar();
Este método mantendrá el bucle en ejecución hasta que no queden más tareas por realizar. En otras palabras: este método se bloqueará hasta que se elimine el último temporizador, transmisión y/o señal.
Asimismo, es imperativo asegurarse de que la aplicación realmente invoque este método una vez. Agregar oyentes al bucle y no ejecutarlo realmente hará que la aplicación se cierre sin esperar a ninguno de los oyentes adjuntos.
Este método NO DEBE llamarse mientras el bucle ya se está ejecutando. Este método PUEDE llamarse más de una vez después de que se haya stop()
o después de que se haya detenido automáticamente porque anteriormente ya no tenía nada que hacer.
El método stop(): void
se puede utilizar para indicarle a un bucle de eventos en ejecución que se detenga.
Este método se considera de uso avanzado y debe usarse con cuidado. Como regla general, normalmente se recomienda dejar que el bucle se detenga automáticamente cuando ya no tenga nada que hacer.
Este método se puede utilizar para indicar explícitamente al bucle de eventos que se detenga:
$loop->addTimer(3.0, función () uso ($loop) {$loop->stop(); });
Llamar a este método en una instancia de bucle que no se está ejecutando actualmente o en una instancia de bucle que ya se ha detenido no tiene ningún efecto.
El método addTimer(float $interval, callable $callback): TimerInterface
se puede utilizar para poner en cola una devolución de llamada que se invocará una vez después del intervalo dado.
El segundo parámetro DEBE ser una función de devolución de llamada del temporizador que acepte la instancia del temporizador como su único parámetro. Si no usa la instancia del temporizador dentro de la función de devolución de llamada del temporizador, PUEDE usar una función que no tiene ningún parámetro.
La función de devolución de llamada del temporizador NO DEBE generar una Exception
. El valor de retorno de la función de devolución de llamada del temporizador se ignorará y no tendrá ningún efecto, por lo que, por motivos de rendimiento, se recomienda no devolver estructuras de datos excesivas.
Este método devuelve una instancia de temporizador. La misma instancia del temporizador también se pasará a la función de devolución de llamada del temporizador como se describe anteriormente. Puede invocar cancelTimer
para cancelar un temporizador pendiente. A diferencia de addPeriodicTimer()
, este método garantizará que la devolución de llamada se invoque solo una vez después del intervalo dado.
$loop->addTimer(0.8, function () {echo 'mundo!' . PHP_EOL; });$loop->addTimer(0.3, function () {echo 'hola '; });
Véase también el ejemplo n.º 1.
Si desea acceder a cualquier variable dentro de su función de devolución de llamada, puede vincular datos arbitrarios a un cierre de devolución de llamada como este:
función hola($nombre, LoopInterface $bucle) {$loop->addTimer(1.0, función () use ($nombre) {echo "hola $nombre"; }); }hola('Probador', $bucle);
Esta interfaz no aplica ninguna resolución de temporizador en particular, por lo que es posible que deba tener especial cuidado si confía en una precisión muy alta con una precisión de milisegundos o inferior. Las implementaciones de bucles de eventos DEBEN funcionar con el mejor esfuerzo posible y DEBEN proporcionar una precisión de al menos milisegundos, a menos que se indique lo contrario. Se sabe que muchas implementaciones de bucles de eventos existentes proporcionan una precisión de microsegundos, pero generalmente no se recomienda confiar en esta alta precisión.
De manera similar, no se garantiza el orden de ejecución de los temporizadores programados para ejecutarse al mismo tiempo (dentro de su posible precisión).
Esta interfaz sugiere que las implementaciones de bucles de eventos DEBEN utilizar una fuente de tiempo monótona si está disponible. Dado que una fuente de tiempo monótona solo está disponible de forma predeterminada a partir de PHP 7.3, las implementaciones de bucles de eventos PUEDEN recurrir al uso de la hora del reloj de pared. Si bien esto no afecta a muchos casos de uso comunes, es una distinción importante para programas que dependen de una alta precisión temporal o de sistemas sujetos a ajustes de tiempo discontinuos (saltos de tiempo). Esto significa que si programa un temporizador para que se active en 30 segundos y luego ajusta el tiempo del sistema hacia adelante en 20 segundos, el temporizador aún DEBE activarse en 30 segundos. Consulte también implementaciones de bucles de eventos para obtener más detalles.
El método addPeriodicTimer(float $interval, callable $callback): TimerInterface
se puede utilizar para poner en cola una devolución de llamada que se invocará repetidamente después del intervalo dado.
El segundo parámetro DEBE ser una función de devolución de llamada del temporizador que acepte la instancia del temporizador como su único parámetro. Si no usa la instancia del temporizador dentro de la función de devolución de llamada del temporizador, PUEDE usar una función que no tiene ningún parámetro.
La función de devolución de llamada del temporizador NO DEBE generar una Exception
. El valor de retorno de la función de devolución de llamada del temporizador se ignorará y no tendrá ningún efecto, por lo que, por motivos de rendimiento, se recomienda no devolver estructuras de datos excesivas.
Este método devuelve una instancia de temporizador. La misma instancia del temporizador también se pasará a la función de devolución de llamada del temporizador como se describe anteriormente. A diferencia de addTimer()
, este método garantizará que la devolución de llamada se invoque infinitamente después del intervalo dado o hasta que invoque cancelTimer
.
$temporizador = $loop->addPeriodicTimer(0.1, function () {echo 'tick!' . PHP_EOL; });$loop->addTimer(1.0, función () use ($loop, $timer) {$loop->cancelTimer($timer);echo 'Listo' . PHP_EOL; });
Véase también el ejemplo n.º 2.
Si desea limitar el número de ejecuciones, puede vincular datos arbitrarios a un cierre de devolución de llamada como este:
función hola($nombre, LoopInterface $bucle) {$n = 3;$bucle->addPeriodicTimer(1.0, función ($temporizador) use ($nombre, $bucle, &$n) {si ($n > 0) { --$n;echo "hola $nombre"; } else {$bucle->cancelTimer($temporizador); } }); }hola('Probador', $bucle);
Esta interfaz no aplica ninguna resolución de temporizador en particular, por lo que es posible que deba tener especial cuidado si confía en una precisión muy alta con una precisión de milisegundos o inferior. Las implementaciones de bucles de eventos DEBEN funcionar con el mejor esfuerzo posible y DEBEN proporcionar una precisión de al menos milisegundos, a menos que se indique lo contrario. Se sabe que muchas implementaciones de bucles de eventos existentes proporcionan una precisión de microsegundos, pero generalmente no se recomienda confiar en esta alta precisión.
De manera similar, no se garantiza el orden de ejecución de los temporizadores programados para ejecutarse al mismo tiempo (dentro de su posible precisión).
Esta interfaz sugiere que las implementaciones de bucles de eventos DEBEN utilizar una fuente de tiempo monótona si está disponible. Dado que una fuente de tiempo monótona solo está disponible de forma predeterminada a partir de PHP 7.3, las implementaciones de bucles de eventos PUEDEN recurrir al uso de la hora del reloj de pared. Si bien esto no afecta a muchos casos de uso comunes, es una distinción importante para programas que dependen de una alta precisión temporal o de sistemas sujetos a ajustes de tiempo discontinuos (saltos de tiempo). Esto significa que si programa un temporizador para que se active en 30 segundos y luego ajusta el tiempo del sistema hacia adelante en 20 segundos, el temporizador aún DEBE activarse en 30 segundos. Consulte también implementaciones de bucles de eventos para obtener más detalles.
Además, los temporizadores periódicos pueden estar sujetos a desviaciones debido a la reprogramación después de cada invocación. Como tal, generalmente no se recomienda confiar en esto para intervalos de alta precisión con una precisión de milisegundos o menos.
El método cancelTimer(TimerInterface $timer): void
se puede utilizar para cancelar un temporizador pendiente.
Consulte también addPeriodicTimer()
y el ejemplo n.º 2.
Llamar a este método en una instancia de temporizador que no se ha agregado a esta instancia de bucle o en un temporizador que ya se ha cancelado no tiene ningún efecto.
El método futureTick(callable $listener): void
se puede utilizar para programar una devolución de llamada que se invocará en un tick futuro del bucle de eventos.
Esto funciona de manera muy similar a los temporizadores con un intervalo de cero segundos, pero no requiere la sobrecarga de programar una cola de temporizadores.
La función de devolución de llamada de tick DEBE poder aceptar cero parámetros.
La función de devolución de llamada de tick NO DEBE generar una Exception
. El valor de retorno de la función de devolución de llamada de tick se ignorará y no tendrá ningún efecto, por lo que, por motivos de rendimiento, se recomienda no devolver estructuras de datos excesivas.
Si desea acceder a cualquier variable dentro de su función de devolución de llamada, puede vincular datos arbitrarios a un cierre de devolución de llamada como este:
función hola($nombre, LoopInterface $bucle) {$loop->futureTick(function () use ($nombre) {echo "hola $nombre"; }); }hola('Probador', $bucle);
A diferencia de los temporizadores, se garantiza que las devoluciones de llamada de ticks se ejecutarán en el orden en que se ponen en cola. Además, una vez que se pone en cola una devolución de llamada, no hay forma de cancelar esta operación.
Esto se utiliza a menudo para dividir tareas más grandes en pasos más pequeños (una forma de multitarea cooperativa).
$bucle->futureTick(función () {echo 'b'; });$loop->futureTick(function () {echo 'c'; }); eco 'a';
Véase también el ejemplo n.º 3.
El método addSignal(int $signal, callable $listener): void
se puede utilizar para registrar un oyente para recibir una notificación cuando este proceso haya captado una señal.
Esto es útil para detectar señales de interrupción del usuario o señales de apagado de herramientas como supervisor
o systemd
.
El segundo parámetro DEBE ser una función de devolución de llamada del oyente que acepte la señal como su único parámetro. Si no usa la señal dentro de la función de devolución de llamada de su oyente, PUEDE usar una función que no tiene ningún parámetro.
La función de devolución de llamada del oyente NO DEBE generar una Exception
. El valor de retorno de la función de devolución de llamada del oyente se ignorará y no tendrá ningún efecto, por lo que, por motivos de rendimiento, se recomienda no devolver estructuras de datos excesivas.
$loop->addSignal(SIGINT, function (int $signal) {echo 'Señal de interrupción del usuario captada'. PHP_EOL; });
Véase también el ejemplo n.º 4.
La señalización solo está disponible en plataformas tipo Unix; Windows no es compatible debido a limitaciones del sistema operativo. Este método puede generar una BadMethodCallException
si las señales no son compatibles con esta plataforma, por ejemplo, cuando faltan las extensiones requeridas.
Nota: Solo se puede agregar un oyente una vez a la misma señal; se ignorará cualquier intento de agregarlo más de una vez.
El método removeSignal(int $signal, callable $listener): void
se puede utilizar para eliminar un oyente de señal agregado previamente.
$bucle->removeSignal(SIGINT, $oyente);
Se ignorará cualquier intento de eliminar oyentes que no estén registrados.
¡Avanzado! Tenga en cuenta que esta API de bajo nivel se considera de uso avanzado. La mayoría de los casos de uso probablemente deberían usar la Stream API legible de nivel superior.
El método addReadStream(resource $stream, callable $callback): void
se puede utilizar para registrar a un oyente y recibir una notificación cuando una transmisión esté lista para leer.
El primer parámetro DEBE ser un recurso de flujo válido que admita la verificación de si está listo para ser leído por esta implementación de bucle. Un recurso de flujo único NO DEBE agregarse más de una vez. En su lugar, llame primero removeReadStream()
o reaccione a este evento con un único oyente y luego envíelo desde este oyente. Este método PUEDE generar una Exception
si el tipo de recurso dado no es compatible con esta implementación de bucle.
El segundo parámetro DEBE ser una función de devolución de llamada de escucha que acepte el recurso de flujo como su único parámetro. Si no utiliza el recurso de transmisión dentro de la función de devolución de llamada de su oyente, PUEDE usar una función que no tiene ningún parámetro.
La función de devolución de llamada del oyente NO DEBE generar una Exception
. El valor de retorno de la función de devolución de llamada del oyente se ignorará y no tendrá ningún efecto, por lo que, por motivos de rendimiento, se recomienda no devolver estructuras de datos excesivas.
Si desea acceder a cualquier variable dentro de su función de devolución de llamada, puede vincular datos arbitrarios a un cierre de devolución de llamada como este:
$loop->addReadStream($stream, function ($stream) use ($name) {echo $name . ' dijo: ' . fread($stream); });
Véase también el ejemplo n.º 11.
Puede invocar removeReadStream()
para eliminar el detector de eventos de lectura para esta transmisión.
No se garantiza el orden de ejecución de los oyentes cuando varias transmisiones están listas al mismo tiempo.
Se sabe que algunas implementaciones de bucles de eventos solo activan el oyente si la transmisión se vuelve legible (activada por borde) y es posible que no se activen si la transmisión ya ha sido legible desde el principio. Esto también implica que es posible que una secuencia no se reconozca como legible cuando aún quedan datos en los buffers de secuencia internos de PHP. Como tal, se recomienda utilizar stream_set_read_buffer($stream, 0);
para deshabilitar el búfer de lectura interno de PHP en este caso.
¡Avanzado! Tenga en cuenta que esta API de bajo nivel se considera de uso avanzado. La mayoría de los casos de uso probablemente deberían utilizar la Stream API grabable de nivel superior.
El método addWriteStream(resource $stream, callable $callback): void
se puede utilizar para registrar un oyente y recibir una notificación cuando una secuencia esté lista para escribir.
El primer parámetro DEBE ser un recurso de flujo válido que admita la verificación de si está listo para escribir mediante esta implementación de bucle. Un recurso de flujo único NO DEBE agregarse más de una vez. En su lugar, llame primero removeWriteStream()
o reaccione a este evento con un único oyente y luego envíelo desde este oyente. Este método PUEDE generar una Exception
si el tipo de recurso dado no es compatible con esta implementación de bucle.
El segundo parámetro DEBE ser una función de devolución de llamada de escucha que acepte el recurso de flujo como su único parámetro. Si no utiliza el recurso de transmisión dentro de la función de devolución de llamada de su oyente, PUEDE usar una función que no tiene ningún parámetro.
La función de devolución de llamada del oyente NO DEBE generar una Exception
. El valor de retorno de la función de devolución de llamada del oyente se ignorará y no tendrá ningún efecto, por lo que, por motivos de rendimiento, se recomienda no devolver estructuras de datos excesivas.
Si desea acceder a cualquier variable dentro de su función de devolución de llamada, puede vincular datos arbitrarios a un cierre de devolución de llamada como este:
$loop->addWriteStream($stream, function ($stream) use ($name) {fwrite($stream, 'Hola' . $name); });
Véase también el ejemplo n.º 12.
Puede invocar removeWriteStream()
para eliminar el detector de eventos de escritura para esta transmisión.
No se garantiza el orden de ejecución de los oyentes cuando varias transmisiones están listas al mismo tiempo.
El método removeReadStream(resource $stream): void
se puede utilizar para eliminar el detector de eventos de lectura para la secuencia determinada.
Eliminar una secuencia del bucle que ya se ha eliminado o intentar eliminar una secuencia que nunca se agregó o que no es válida no tiene ningún efecto.
El método removeWriteStream(resource $stream): void
se puede utilizar para eliminar el detector de eventos de escritura para la secuencia determinada.
Eliminar una secuencia del bucle que ya se ha eliminado o intentar eliminar una secuencia que nunca se agregó o que no es válida no tiene ningún efecto.
La forma recomendada de instalar esta biblioteca es a través de Composer. ¿Nuevo en el compositor?
Una vez lanzado, este proyecto seguirá a SemVer. Por el momento, esto instalará la última versión de desarrollo:
el compositor requiere reacción/bucle de eventos:^3@dev
Consulte también el CHANGELOG para obtener detalles sobre las actualizaciones de versiones.
Este proyecto pretende ejecutarse en cualquier plataforma y, por lo tanto, no requiere ninguna extensión de PHP y admite la ejecución desde PHP 7.1 hasta PHP 8+ actual. Se recomienda encarecidamente utilizar la última versión de PHP compatible para este proyecto.
Se sugiere instalar cualquiera de las extensiones de bucle de eventos, pero es completamente opcional. Consulte también implementaciones de bucles de eventos para obtener más detalles.
Para ejecutar el conjunto de pruebas, primero debe clonar este repositorio y luego instalar todas las dependencias a través de Composer:
instalación del compositor
Para ejecutar el conjunto de pruebas, vaya a la raíz del proyecto y ejecute:
proveedor/bin/phpunit
MIT, ver archivo de LICENCIA.
Consulte nuestro componente Stream para obtener más información sobre cómo se utilizan las transmisiones en aplicaciones del mundo real.
Consulte la wiki de nuestros usuarios y los dependientes de Packagist para obtener una lista de paquetes que utilizan EventLoop en aplicaciones del mundo real.