O loop de eventos do reator principal do ReactPHP que as bibliotecas podem usar para E/S com eventos.
Versão de desenvolvimento: esta ramificação contém o código para a próxima versão v3. Para o código da versão estável atual v1, verifique o branch
1.x
A próxima versão v3 será o caminho a seguir para este pacote. No entanto, ainda ofereceremos suporte ativo à v1 para aqueles que ainda não estão na versão mais recente. Consulte também as instruções de instalação para obter mais detalhes.
Para que as bibliotecas baseadas em assíncronas sejam interoperáveis, elas precisam usar o mesmo loop de eventos. Este componente fornece um LoopInterface
comum que qualquer biblioteca pode ter como alvo. Isso permite que eles sejam usados no mesmo loop, com uma única chamada run()
controlada pelo usuário.
Índice
Exemplo de início rápido
Uso
correr()
parar()
adicionarTimer()
addPeriodicTimer()
cancelarTimer()
futureTick()
adicionarSinal()
removerSignal()
addReadStream()
addWriteStream()
removeReadStream()
removeWriteStream()
StreamSelectLoop
ExtEventLoop
ExtEvLoop
ExtUvLoop
Métodos de loop
Execução automática de loop
pegar()
Laço
Implementações de loop
LoopInterface
Instalar
Testes
Licença
Mais
Aqui está um servidor HTTP assíncrono construído apenas com o loop de eventos.
<?phpuse ReactEventLoopLoop;require __DIR__ . '/vendor/autoload.php';$servidor = stream_socket_server('tcp://127.0.0.1:8080');stream_set_blocking($servidor, falso); Loop::addReadStream($servidor, função ($servidor) {$conn = stream_socket_accept($servidor);$data = "HTTP/1.1 200 OKrnContent-Length: 3rnrnHin"; Loop::addWriteStream($conn, função ($conn) use (&$dados) {$escrito = fwrite($conn, $dados);if ($escrito === strlen($dados)) {fclose($conn ); Loop::removeWriteStream($conn); } else {$dados = substr($dados, $escritos); } }); }); Loop::addPeriodicTimer(5, function () {$memory = memory_get_usage() / 1024;$formatted = number_format($memory, 3).'K';echo "Uso de memória atual: {$formatted}n"; });
Veja também os exemplos.
Aplicativos típicos usariam a classe Loop
para usar o loop de eventos padrão como este:
use ReactEventLoopLoop;$timer = Loop::addPeriodicTimer(0.1, function () {echo 'Tick' . PHP_EOL; }); Loop::addTimer(1.0, function () use ($timer) { Loop::cancelTimer($timer);echo 'Concluído' . PHP_EOL; });
Como alternativa, você também pode criar explicitamente uma instância de loop de eventos no início, reutilizá-la em todo o programa e finalmente executá-la no final do programa assim:
$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 'Concluído' . PHP_EOL; });$loop->executar();
Enquanto o primeiro é mais conciso, o segundo é mais explícito. Em ambos os casos, o programa executaria exatamente as mesmas etapas.
A instância do loop de eventos é criada no início do programa. Isso é feito implicitamente na primeira vez que você chama a classe Loop
(ou instanciando manualmente qualquer uma das implementações de loop).
O loop de eventos é usado diretamente ou passado como uma instância para a biblioteca e o código do aplicativo. Neste exemplo, um temporizador periódico é registrado com o loop de eventos que simplesmente gera Tick
a cada fração de segundo até que outro temporizador interrompa o temporizador periódico após um segundo.
O loop de eventos é executado no final do programa. Isso é feito automaticamente ao usar a classe Loop
ou explicitamente com uma única chamada run()
no final do programa.
A partir da v1.2.0
, é altamente recomendável usar a classe Loop
. As instruções de loop explícitas ainda são válidas e ainda podem ser úteis em algumas aplicações, especialmente durante um período de transição para um estilo mais conciso.
A classe Loop
existe como um acessador global conveniente para o loop de eventos.
A classe Loop
fornece todos os métodos que existem no LoopInterface
como métodos estáticos:
correr()
parar()
adicionarTimer()
addPeriodicTimer()
cancelarTimer()
futureTick()
adicionarSinal()
removerSignal()
addReadStream()
addWriteStream()
removeReadStream()
removeWriteStream()
Se você estiver trabalhando com o loop de eventos no código do seu aplicativo, geralmente é mais fácil fazer interface direta com os métodos estáticos definidos na classe Loop
assim:
use ReactEventLoopLoop;$timer = Loop::addPeriodicTimer(0.1, function () {echo 'Tick' . PHP_EOL; }); Loop::addTimer(1.0, function () use ($timer) { Loop::cancelTimer($timer);echo 'Concluído' . PHP_EOL; });
Por outro lado, se você estiver familiarizado com programação orientada a objetos (OOP) e injeção de dependência (DI), talvez queira injetar uma instância de loop de eventos e invocar métodos de instância no LoopInterface
assim:
usar ReactEventLoopLoop; usar ReactEventLoopLoopInterface;class Greeter {privado $loop;função pública __construct(LoopInterface $loop) {$this->loop = $loop; }função pública saudação(string $nome) {$this->loop->addTimer(1.0, function () use ($nome) {echo 'Olá ' . $nome . '!' . PHP_EOL; }); } }$greeter = new Greeter(Loop::get());$greeter->greet('Alice');$greeter->greet('Bob');
Cada chamada de método estático será encaminhada como está para a instância do loop de evento subjacente usando a chamada Loop::get()
internamente. Consulte LoopInterface
para obter mais detalhes sobre os métodos disponíveis.
Ao usar a classe Loop
, ela executará automaticamente o loop no final do programa. Isso significa que o exemplo a seguir agendará um cronômetro e executará automaticamente o programa até que o evento do cronômetro seja acionado:
usar ReactEventLoopLoop; Loop::addTimer(1.0, function() {echo 'Olá' . PHP_EOL; });
A partir da v1.2.0
, é altamente recomendável usar a classe Loop
dessa forma e omitir quaisquer chamadas run()
explícitas. Por razões de BC, o método run()
explícito ainda é válido e ainda pode ser útil em algumas aplicações, especialmente para um período de transição para um estilo mais conciso.
Se você não deseja que o Loop
seja executado automaticamente, você pode run()
ou stop()
explicitamente. Isso pode ser útil se você estiver usando um manipulador de exceções global como este:
usar ReactEventLoopLoop; Loop::addTimer(10.0, function() {echo 'Nunca acontece'; });set_exception_handler(function (Throwable $e) {echo 'Erro: ' . $e->getMessage() . PHP_EOL; Loop::parar(); });lançar new RuntimeException('Demo');
O método get(): LoopInterface
pode ser usado para obter a instância do loop de eventos atualmente ativa.
Este método sempre retornará a mesma instância do loop de eventos durante toda a vida útil do seu aplicativo.
use ReactEventLoopLoop;use ReactEventLoopLoopInterface;$loop = Loop::get();assert($loop instanceof LoopInterface);assert($loop === Loop::get());
Isso é particularmente útil se você estiver usando programação orientada a objetos (OOP) e injeção de dependência (DI). Nesse caso, você pode querer injetar uma instância de loop de eventos e invocar métodos de instância no LoopInterface
assim:
usar ReactEventLoopLoop; usar ReactEventLoopLoopInterface;class Greeter {privado $loop;função pública __construct(LoopInterface $loop) {$this->loop = $loop; }função pública saudação(string $nome) {$this->loop->addTimer(1.0, function () use ($nome) {echo 'Olá ' . $nome . '!' . PHP_EOL; }); } }$greeter = new Greeter(Loop::get());$greeter->greet('Alice');$greeter->greet('Bob');
Consulte LoopInterface
para obter mais detalhes sobre os métodos disponíveis.
Além do LoopInterface
, há diversas implementações de loop de eventos fornecidas.
Todos os loops de eventos oferecem suporte a estes recursos:
Pesquisa de descritor de arquivo
Temporizadores únicos
Temporizadores periódicos
Execução adiada no tick de loop futuro
Para a maioria dos consumidores deste pacote, a implementação subjacente do loop de eventos é um detalhe de implementação. Você deve usar a classe Loop
para criar automaticamente uma nova instância.
Avançado! Se você precisar explicitamente de uma determinada implementação de loop de eventos, poderá instanciar manualmente uma das classes a seguir. Observe que pode ser necessário instalar primeiro as extensões PHP necessárias para a respectiva implementação do loop de eventos ou elas lançarão uma BadMethodCallException
na criação.
Um loop de eventos baseado em stream_select()
.
Isso usa a função stream_select()
e é a única implementação que funciona imediatamente com PHP.
Este loop de eventos funciona imediatamente em qualquer versão do PHP. Isso significa que nenhuma instalação é necessária e esta biblioteca funciona em todas as plataformas e versões de PHP suportadas. Da mesma forma, a classe Loop
usará esse loop de eventos por padrão se você não instalar nenhuma das extensões de loop de eventos listadas abaixo.
Nos bastidores, ele faz uma simples chamada de sistema select
. Esta chamada de sistema é limitada ao número máximo do descritor de arquivo FD_SETSIZE
(dependente da plataforma, geralmente 1024) e é dimensionada com O(m)
( m
sendo o número máximo do descritor de arquivo passado). Isso significa que você pode ter problemas ao lidar com milhares de fluxos simultaneamente e pode querer usar uma das implementações alternativas de loop de eventos listadas abaixo neste caso. Se o seu caso de uso estiver entre os muitos casos de uso comuns que envolvem o tratamento de apenas dezenas ou algumas centenas de fluxos de uma vez, essa implementação de loop de eventos terá um desempenho muito bom.
Se você quiser usar manipulação de sinal (veja também addSignal()
abaixo), esta implementação de loop de eventos requer ext-pcntl
. Esta extensão está disponível apenas para plataformas do tipo Unix e não oferece suporte ao Windows. Geralmente é instalado como parte de muitas distribuições PHP. Se esta extensão estiver faltando (ou se você estiver executando no Windows), a manipulação de sinal não será suportada e gerará uma BadMethodCallException
.
Este loop de eventos é conhecido por depender do tempo do relógio para agendar temporizadores futuros ao usar qualquer versão anterior ao PHP 7.3, porque uma fonte de tempo monotônica só está disponível a partir do PHP 7.3 ( hrtime()
). Embora isto não afete muitos casos de uso comuns, esta é uma distinção importante para programas que dependem de uma alta precisão de tempo ou em sistemas que estão sujeitos a ajustes de tempo descontínuos (saltos de tempo). Isso significa que se você programar um cronômetro para disparar em 30s no PHP <7.3 e então ajustar o tempo do sistema em 20s, o cronômetro poderá disparar em 10s. Veja também addTimer()
para mais detalhes.
Um loop de eventos baseado em ext-event
.
Isso usa a extensão PECL event
, que fornece uma interface para a biblioteca libevent
. O próprio libevent
suporta vários backends específicos do sistema (epoll, kqueue).
Este loop é conhecido por funcionar com PHP 7.1 até PHP 8+.
Um loop de eventos baseado em ext-ev
.
Este loop usa a extensão ev
PECL, que fornece uma interface para a biblioteca libev
. O próprio libev
suporta vários backends específicos do sistema (epoll, kqueue).
Este loop é conhecido por funcionar com PHP 7.1 até PHP 8+.
Um loop de eventos baseado em ext-uv
.
Este loop usa a extensão uv
PECL, que fornece uma interface para a biblioteca libuv
. O próprio libuv
suporta vários backends específicos do sistema (epoll, kqueue).
Este loop é conhecido por funcionar com PHP 7.1 até PHP 8+.
O método run(): void
pode ser usado para executar o loop de eventos até que não haja mais tarefas para executar.
Para muitos aplicativos, esse método é a única invocação diretamente visível no loop de eventos. Como regra geral, geralmente é recomendado anexar tudo à mesma instância de loop e, em seguida, executar o loop uma vez na extremidade inferior do aplicativo.
$loop->executar();
Este método manterá o loop em execução até que não haja mais tarefas a serem executadas. Em outras palavras: Este método irá bloquear até que o último temporizador, fluxo e/ou sinal seja removido.
Da mesma forma, é imperativo garantir que o aplicativo realmente invoque esse método uma vez. Adicionar ouvintes ao loop e deixar de executá-lo resultará na saída do aplicativo sem realmente esperar por nenhum dos ouvintes anexados.
Este método NÃO DEVE ser chamado enquanto o loop já estiver em execução. Este método PODE ser chamado mais de uma vez depois de ter sido explicitamente solicitado stop()
ou depois de ter parado automaticamente porque anteriormente não tinha mais nada para fazer.
O método stop(): void
pode ser usado para instruir um loop de eventos em execução a parar.
Este método é considerado de uso avançado e deve ser usado com cuidado. Como regra geral, geralmente é recomendado deixar o loop parar automaticamente apenas quando não houver mais nada para fazer.
Este método pode ser usado para instruir explicitamente o loop de eventos a parar:
$loop->addTimer(3.0, function() use ($loop) {$loop->stop(); });
Chamar esse método em uma instância de loop que não está em execução no momento ou em uma instância de loop que já foi interrompida não tem efeito.
O método addTimer(float $interval, callable $callback): TimerInterface
pode ser usado para enfileirar um retorno de chamada para ser invocado uma vez após o intervalo determinado.
O segundo parâmetro DEVE ser uma função de retorno de chamada de timer que aceita a instância do timer como seu único parâmetro. Se você não usar a instância do timer dentro da função de retorno de chamada do timer, você PODE usar uma função que não possui nenhum parâmetro.
A função de retorno de chamada do timer NÃO DEVE lançar uma Exception
. O valor de retorno da função de retorno de chamada do timer será ignorado e não terá efeito, portanto, por motivos de desempenho, é recomendável não retornar nenhuma estrutura de dados excessiva.
Este método retorna uma instância de timer. A mesma instância do timer também será passada para a função de retorno de chamada do timer conforme descrito acima. Você pode invocar cancelTimer
para cancelar um cronômetro pendente. Ao contrário de addPeriodicTimer()
, este método garantirá que o retorno de chamada será invocado apenas uma vez após o intervalo determinado.
$loop->addTimer(0.8, function() {echo 'mundo!' . PHP_EOL; });$loop->addTimer(0.3, function() {echo 'olá'; });
Veja também o exemplo nº 1.
Se quiser acessar qualquer variável dentro da sua função de retorno de chamada, você pode vincular dados arbitrários a um encerramento de retorno de chamada como este:
função olá($nome, LoopInterface $loop) {$loop->addTimer(1.0, function() use ($nome) {echo "olá $nome"; }); }olá('Testador', $loop);
Esta interface não impõe nenhuma resolução de temporizador específica, portanto, deve-se tomar cuidado especial se você confiar em uma precisão muito alta com precisão de milissegundos ou menos. As implementações de loop de eventos DEVEM funcionar com base no melhor esforço e DEVEM fornecer precisão de pelo menos milissegundos, salvo indicação em contrário. Sabe-se que muitas implementações de loop de eventos existentes fornecem precisão de microssegundos, mas geralmente não é recomendado confiar nessa alta precisão.
Da mesma forma, a ordem de execução dos temporizadores programados para serem executados ao mesmo tempo (dentro da sua precisão possível) não é garantida.
Esta interface sugere que as implementações de loop de eventos DEVEM usar uma fonte de tempo monotônica, se disponível. Dado que uma fonte de tempo monotônica só está disponível a partir do PHP 7.3 por padrão, as implementações de loop de eventos PODEM voltar a usar o tempo do relógio de parede. Embora isto não afete muitos casos de uso comuns, esta é uma distinção importante para programas que dependem de uma alta precisão de tempo ou em sistemas que estão sujeitos a ajustes de tempo descontínuos (saltos de tempo). Isso significa que se você programar um cronômetro para disparar em 30 segundos e depois ajustar o tempo do sistema em 20 segundos, o cronômetro ainda DEVE disparar em 30 segundos. Consulte também implementações de loop de eventos para obter mais detalhes.
O método addPeriodicTimer(float $interval, callable $callback): TimerInterface
pode ser usado para enfileirar um retorno de chamada para ser invocado repetidamente após o intervalo determinado.
O segundo parâmetro DEVE ser uma função de retorno de chamada de timer que aceita a instância do timer como seu único parâmetro. Se você não usar a instância do timer dentro da função de retorno de chamada do timer, você PODE usar uma função que não possui nenhum parâmetro.
A função de retorno de chamada do timer NÃO DEVE lançar uma Exception
. O valor de retorno da função de retorno de chamada do timer será ignorado e não terá efeito, portanto, por motivos de desempenho, é recomendável não retornar nenhuma estrutura de dados excessiva.
Este método retorna uma instância de timer. A mesma instância do timer também será passada para a função de retorno de chamada do timer conforme descrito acima. Ao contrário de addTimer()
, este método garantirá que o retorno de chamada será invocado infinitamente após o intervalo determinado ou até que você invoque cancelTimer
.
$timer = $loop->addPeriodicTimer(0.1, function () {echo 'tick!' . PHP_EOL; });$loop->addTimer(1.0, function () use ($loop, $timer) {$loop->cancelTimer($timer);echo 'Concluído' . PHP_EOL; });
Veja também o exemplo nº 2.
Se quiser limitar o número de execuções, você pode vincular dados arbitrários a um fechamento de retorno de chamada como este:
função olá($nome, LoopInterface $loop) {$n = 3;$loop->addPeriodicTimer(1.0, function ($timer) use ($name, $loop, &$n) {if ($n > 0) { --$n;echo "olá $nome"; } else {$loop->cancelTimer($timer); } }); }olá('Testador', $loop);
Esta interface não impõe nenhuma resolução de temporizador específica, portanto, deve-se tomar cuidado especial se você confiar em uma precisão muito alta com precisão de milissegundos ou menos. As implementações de loop de eventos DEVEM funcionar com base no melhor esforço e DEVEM fornecer precisão de pelo menos milissegundos, salvo indicação em contrário. Sabe-se que muitas implementações de loop de eventos existentes fornecem precisão de microssegundos, mas geralmente não é recomendado confiar nessa alta precisão.
Da mesma forma, a ordem de execução dos temporizadores programados para serem executados ao mesmo tempo (dentro da sua precisão possível) não é garantida.
Esta interface sugere que as implementações de loop de eventos DEVEM usar uma fonte de tempo monotônica, se disponível. Dado que uma fonte de tempo monotônica só está disponível a partir do PHP 7.3 por padrão, as implementações de loop de eventos PODEM voltar a usar o tempo do relógio de parede. Embora isto não afete muitos casos de uso comuns, esta é uma distinção importante para programas que dependem de uma alta precisão de tempo ou em sistemas que estão sujeitos a ajustes de tempo descontínuos (saltos de tempo). Isso significa que se você programar um cronômetro para disparar em 30 segundos e depois ajustar o tempo do sistema em 20 segundos, o cronômetro ainda DEVE disparar em 30 segundos. Consulte também implementações de loop de eventos para obter mais detalhes.
Além disso, os temporizadores periódicos podem estar sujeitos a desvios devido ao reprogramamento após cada invocação. Como tal, geralmente não é recomendado confiar nisso para intervalos de alta precisão com precisão de milissegundos ou menos.
O método cancelTimer(TimerInterface $timer): void
pode ser usado para cancelar um cronômetro pendente.
Veja também addPeriodicTimer()
e exemplo #2.
Chamar esse método em uma instância de timer que não foi adicionada a essa instância de loop ou em um timer que já foi cancelado não tem efeito.
O método futureTick(callable $listener): void
pode ser usado para agendar um retorno de chamada a ser invocado em um tick futuro do loop de eventos.
Isso funciona de maneira muito semelhante aos temporizadores com intervalo de zero segundos, mas não requer a sobrecarga de agendamento de uma fila de temporizador.
A função de retorno de chamada do tick DEVE ser capaz de aceitar zero parâmetros.
A função de retorno de chamada tick NÃO DEVE lançar uma Exception
. O valor de retorno da função de retorno de chamada tick será ignorado e não terá efeito, portanto, por motivos de desempenho, é recomendável não retornar nenhuma estrutura de dados excessiva.
Se quiser acessar qualquer variável dentro da sua função de retorno de chamada, você pode vincular dados arbitrários a um encerramento de retorno de chamada como este:
função olá($nome, LoopInterface $loop) {$loop->futureTick(função() use ($nome) {echo "olá $nome"; }); }olá('Testador', $loop);
Ao contrário dos temporizadores, os retornos de chamada de tick têm garantia de serem executados na ordem em que são enfileirados. Além disso, quando um retorno de chamada é enfileirado, não há como cancelar esta operação.
Isto é frequentemente usado para dividir tarefas maiores em etapas menores (uma forma de multitarefa cooperativa).
$loop->futureTick(função() {echo 'b'; });$loop->futureTick(function () {echo 'c'; });echo 'a';
Veja também o exemplo nº 3.
O método addSignal(int $signal, callable $listener): void
pode ser usado para registrar um ouvinte para ser notificado quando um sinal for capturado por este processo.
Isso é útil para capturar sinais de interrupção do usuário ou sinais de desligamento de ferramentas como supervisor
ou systemd
.
O segundo parâmetro DEVE ser uma função de retorno de chamada do ouvinte que aceita o sinal como seu único parâmetro. Se você não usar o sinal dentro da função de retorno de chamada do ouvinte, você PODE usar uma função que não possui nenhum parâmetro.
A função de retorno de chamada do ouvinte NÃO DEVE lançar uma Exception
. O valor de retorno da função de retorno de chamada do ouvinte será ignorado e não terá efeito, portanto, por motivos de desempenho, é recomendável não retornar nenhuma estrutura de dados excessiva.
$loop->addSignal(SIGINT, function (int $signal) {echo 'Sinal de interrupção do usuário capturado' . PHP_EOL; });
Veja também o exemplo #4.
A sinalização está disponível apenas em plataformas do tipo Unix; o Windows não é compatível devido a limitações do sistema operacional. Este método pode lançar uma BadMethodCallException
se os sinais não forem suportados nesta plataforma, por exemplo, quando faltam extensões necessárias.
Nota: Um ouvinte só pode ser adicionado uma vez ao mesmo sinal; qualquer tentativa de adicioná-lo mais de uma vez será ignorada.
O método removeSignal(int $signal, callable $listener): void
pode ser usado para remover um ouvinte de sinal adicionado anteriormente.
$loop->removeSignal(SIGINT, $listener);
Quaisquer tentativas de remover ouvintes que não estejam registrados serão ignoradas.
Avançado! Observe que esta API de baixo nível é considerada de uso avançado. A maioria dos casos de uso provavelmente deveria usar a API Stream legível de nível superior.
O método addReadStream(resource $stream, callable $callback): void
pode ser usado para registrar um ouvinte para ser notificado quando um fluxo estiver pronto para leitura.
O primeiro parâmetro DEVE ser um recurso de fluxo válido que suporte a verificação se está pronto para leitura por esta implementação de loop. Um único recurso de fluxo NÃO DEVE ser adicionado mais de uma vez. Em vez disso, chame removeReadStream()
primeiro ou reaja a esse evento com um único ouvinte e, em seguida, despache a partir desse ouvinte. Este método PODE lançar uma Exception
se o tipo de recurso fornecido não for suportado por esta implementação de loop.
O segundo parâmetro DEVE ser uma função de retorno de chamada do ouvinte que aceita o recurso de fluxo como seu único parâmetro. Se você não usar o recurso stream dentro da função de retorno de chamada do ouvinte, você PODE usar uma função que não possui nenhum parâmetro.
A função de retorno de chamada do ouvinte NÃO DEVE lançar uma Exception
. O valor de retorno da função de retorno de chamada do ouvinte será ignorado e não terá efeito, portanto, por motivos de desempenho, é recomendável não retornar nenhuma estrutura de dados excessiva.
Se quiser acessar qualquer variável dentro da sua função de retorno de chamada, você pode vincular dados arbitrários a um fechamento de retorno de chamada como este:
$loop->addReadStream($stream, function ($stream) use ($name) {echo $name . ' disse: ' . fread($stream); });
Veja também o exemplo #11.
Você pode invocar removeReadStream()
para remover o ouvinte de evento de leitura deste fluxo.
A ordem de execução dos ouvintes quando vários fluxos ficam prontos ao mesmo tempo não é garantida.
Sabe-se que algumas implementações de loop de eventos acionam o ouvinte apenas se o fluxo se tornar legível (acionado pela borda) e podem não ser acionados se o fluxo já estiver legível desde o início. Isso também implica que um stream pode não ser reconhecido como legível quando os dados ainda são deixados nos buffers de stream internos do PHP. Como tal, é recomendado usar stream_set_read_buffer($stream, 0);
para desabilitar o buffer de leitura interno do PHP neste caso.
Avançado! Observe que esta API de baixo nível é considerada de uso avançado. A maioria dos casos de uso provavelmente deveria usar a API Stream gravável de nível superior.
O método addWriteStream(resource $stream, callable $callback): void
pode ser usado para registrar um ouvinte para ser notificado quando um fluxo estiver pronto para gravação.
O primeiro parâmetro DEVE ser um recurso de fluxo válido que suporte a verificação se está pronto para escrever por meio desta implementação de loop. Um único recurso de fluxo NÃO DEVE ser adicionado mais de uma vez. Em vez disso, chame removeWriteStream()
primeiro ou reaja a esse evento com um único ouvinte e, em seguida, despache a partir desse ouvinte. Este método PODE lançar uma Exception
se o tipo de recurso fornecido não for suportado por esta implementação de loop.
O segundo parâmetro DEVE ser uma função de retorno de chamada do ouvinte que aceita o recurso de fluxo como seu único parâmetro. Se você não usar o recurso stream dentro da função de retorno de chamada do ouvinte, você PODE usar uma função que não possui nenhum parâmetro.
A função de retorno de chamada do ouvinte NÃO DEVE lançar uma Exception
. O valor de retorno da função de retorno de chamada do ouvinte será ignorado e não terá efeito, portanto, por motivos de desempenho, é recomendável não retornar nenhuma estrutura de dados excessiva.
Se quiser acessar qualquer variável dentro da sua função de retorno de chamada, você pode vincular dados arbitrários a um encerramento de retorno de chamada como este:
$loop->addWriteStream($stream, função ($stream) use ($nome) {fwrite($stream, 'Olá' . $nome); });
Veja também o exemplo #12.
Você pode invocar removeWriteStream()
para remover o ouvinte de evento de gravação deste fluxo.
A ordem de execução dos ouvintes quando vários fluxos ficam prontos ao mesmo tempo não é garantida.
O método removeReadStream(resource $stream): void
pode ser usado para remover o ouvinte de evento de leitura para um determinado fluxo.
Remover um fluxo do loop que já foi removido ou tentar remover um fluxo que nunca foi adicionado ou é inválido não tem efeito.
O método removeWriteStream(resource $stream): void
pode ser usado para remover o ouvinte de evento de gravação para um determinado fluxo.
Remover um fluxo do loop que já foi removido ou tentar remover um fluxo que nunca foi adicionado ou é inválido não tem efeito.
A forma recomendada de instalar esta biblioteca é através do Composer. Novo no Compositor?
Uma vez lançado, este projeto seguirá o SemVer. No momento, isso instalará a versão de desenvolvimento mais recente:
compositor requer reação/loop de evento:^3@dev
Consulte também o CHANGELOG para obter detalhes sobre atualizações de versão.
Este projeto visa rodar em qualquer plataforma e, portanto, não requer nenhuma extensão PHP e suporta execução em PHP 7.1 até o atual PHP 8+. É altamente recomendável usar a versão mais recente do PHP suportada para este projeto.
A instalação de qualquer uma das extensões de loop de eventos é sugerida, mas é totalmente opcional. Consulte também implementações de loop de eventos para obter mais detalhes.
Para executar o conjunto de testes, primeiro você precisa clonar este repositório e depois instalar todas as dependências através do Composer:
instalação do compositor
Para executar o conjunto de testes, vá até a raiz do projeto e execute:
fornecedor/bin/phpunit
MIT, consulte o arquivo LICENSE.
Consulte nosso componente Stream para obter mais informações sobre como os streams são usados em aplicativos do mundo real.
Consulte o wiki de nossos usuários e os dependentes do Packagist para obter uma lista de pacotes que usam o EventLoop em aplicativos do mundo real.