Você está na página 1de 30

(https://www.treinaweb.com.

br/blog/)
Acesse A Treinaweb (Https://Www.treinaweb.com.br)
(https://www.facebook.com/TreinaWeb/) (https://youtube.com.br/treinaweb)

Ferramentas Para Devs (Https://Www.treinaweb.com.br/Ferramentas-Para-Desenvolvedores/)


(https://instagram.com/treinaweb) (https://twitter.com/treinaweb)

Conheça Nossos Cursos (Https://Www.treinaweb.com.br/Cursos-Online)

PHP ( HTTPS :// WW W.T REI NA WEB. CO M. BR/BL O G/C AT EG ORIA/ D ESEN V OL V IMEN TO- BAC K- END / P H P / )

Curta nossa
Introduçao
̃ à programaçao
̃ assíncrona
em PHP usando o ReactPHP
Kennedy Tedesco (Https://Www.treinaweb.com.br/Blog/Author/Kennedy-Tedesco/) 13 De Maio De 2019 0

5 / 5 ( 5 votes )

Antes de entrarmos no comparativo do modelo síncrono versus


assíncrono, veremos uma introdução, o essencial, sobre como uma
requisição funciona em uma aplicação PHP tradicional.

A maior parte das aplicações escritas em PHP funcionam no clássico


modelo de requisição e resposta de curto tempo de vida. Uma
requisição é feita, o código é interpretado e depois compilado, a
execução é realizada, dados são retornados e tudo é descarregado da
memória na sequência, tudo acontece de forma isolada, sem
compartilhar contexto. De forma simplificada, esse é o ciclo de vida da
execução de um script no PHP a cada nova requisição feita.

Você pode estar imaginando que isso é muito custoso, ter sempre que
passar pela interpretação e compilação a cada nova requisição. Você
está certo. Mas o PHP implementa mecanismos que otimizam esse
processo, para não ter que interpretar e compilar o código o tempo
todo. O PHP interpreta os códigos e os compila (de forma implícita, ou
seja, quando ele julga necessário) para bytecodes (uma versão
intermediária de código) e coloca isso em memória compartilhada
quando ele percebe que aquela parte é muito requisitada/utilizada
(tarefa da extensão nativa OPCache). Além disso, o PHP implementa
outros mecanismos (de mais baixo nível) de otimização da execução
desse código intermediário.
De qualquer forma, mesmo com os mecanismos de otimização, a
(https://www.treinaweb.com.br/blog/)
Acesse A Treinaweb (Https://Www.treinaweb.com.br)
essência do modelo de requisição e resposta (https://youtube.com.br/treinaweb)
(https://www.facebook.com/TreinaWeb/) se mantém a mesma. O
diagrama abaixo exemplifica como funciona esse ciclo de execução:
Ferramentas Para Devs (Https://Www.treinaweb.com.br/Ferramentas-Para-Desenvolvedores/)
(https://instagram.com/treinaweb) (https://twitter.com/treinaweb)

Conheça Nossos Cursos (Https://Www.treinaweb.com.br/Cursos-Online)

Curta nossa

Esse diagrama encurtou propositalmente uma etapa, a que passa pelo


PHP-FPM, um gerenciador de processos, muito usado junto ao Nginx
(servidor web), pois poderíamos ter um artigo só para falar sobre ele. A
ideia aqui é entender o básico de como a requisição passa pelo
servidor web e depois é retornada para o cliente. O PHP-FPM dispõe de
pools de processos, ele cria, controla e encerra, de acordo com a
demanda (o que o Nginx está encaminhando pra ele) e capacidade
do hardware para tal (memória, principalmente).

Modelo síncrono
Num ambiente síncrono (tradicional) as instruções (partes) do
programa são executadas uma por uma e apenas uma por vez, de
forma sequencial:

<?php

echo "Hello ";

sleep(4); // Espera 4 segundos

echo "World";

Esse script vai demorar 4 segundos para ser executado e finalizado. A


execução acontece linha por linha, de forma bloqueante. Se uma
instrução precisa aguardar algum tempo (seja para ler algo do disco
ou fazer alguma operação na rede), isso terá de ser concluído para
que a próxima instrução seja executada e até mesmo para que ela use
os dados previamente recuperados/preparados. Ou seja, parte-se da
premissa de que a instrução anterior precisa ter sido concluída com
sucesso (sem erros) para que uma nova seja executada
(dependência).
(https://www.treinaweb.com.br/blog/)
Acesse A Treinaweb (Https://Www.treinaweb.com.br)
(https://www.facebook.com/TreinaWeb/) (https://youtube.com.br/treinaweb)

Ferramentas Para Devs (Https://Www.treinaweb.com.br/Ferramentas-Para-Desenvolvedores/)


(https://instagram.com/treinaweb) (https://twitter.com/treinaweb)

Conheça Nossos Cursos (Https://Www.treinaweb.com.br/Cursos-Online)

Esse modelo funciona muito bem pra operações que usam mais CPU
Curta nossa
que I/O, pois a resolução de uma operação na CPU é muito mais
eficiente do que uma operação que envolva I/O (uma requisição na
rede, a leitura de um arquivo, esse tipo de operação é de alta latência).

Só que pense no seguinte problema: você decidiu implementar uma


tarefa que precisa verificar se os links de um site estão todos online. No
modelo síncrono, teríamos que partir da primeira requisição, aguardar
o resultado dela (momento de ociosidade do programa) e então partir
para próxima seguindo o mesmo fluxo até a última (sempre de forma
sequencial e uma só iniciando após a finalização da outra).

Mas, não seria melhor ao invés de esperarmos a primeira requisição


ser finalizada já inicializarmos as outras requisições e depois de um
tempo voltar para pegar os resultados produzidos por elas? Pois bem,
essa é a ideia central do modelo assíncrono, ele minimiza a ociosidade
do programa alternando entre as tarefas. Num código assíncrono as
tarefas são intercaladas sem precisar envolver novas threads, ou seja,
de forma single-thread (como funciona o PHP e NodeJS, por exemplo).

Modelo assíncrono
Um código assíncrono lida com dependências e ordem de execução
de eventos, ou seja, lida basicamente com tempo. É comum associar
assincronismo com paralelismo, pois o assincronismo dá essa
sensação que muita coisa está sendo executada no mesmo instante
de tempo, no entanto, ao invés disso, no assincronismo muita coisa é
feita ao mesmo tempo (concorrentemente) só que uma coisa por vez,
nunca no mesmo instante de tempo (o fluxo de execução alterna entre
as tarefas). Não existe paralelismo num código assíncrono, ou seja, um
código assíncrono não tem suas tarefas distribuídas em múltiplas
unidades de processamento, igual comentamos anteriormente, é
single-thread (apesar de ser possível atingir paralelismo com
assincronismo num ambiente multi-thread, mas foge do escopo do
(https://www.treinaweb.com.br/blog/)
Acesse A Treinaweb (Https://Www.treinaweb.com.br)
nosso artigo e normalmente necessita de algum
(https://www.facebook.com/TreinaWeb/) caso de uso bem
(https://youtube.com.br/treinaweb)
específico, devido às dificuldades técnicas de se implementar e
sincronizarFerramentas Para Devs (Https://Www.treinaweb.com.br/Ferramentas-Para-Desenvolvedores/)
a comunicação).
(https://instagram.com/treinaweb) (https://twitter.com/treinaweb)

Um código assíncrono continua


Conheça executando
Nossos Cursosuma tarefa por vez, ele
(Https://Www.treinaweb.com.br/Cursos-Online)
apenas não fica preso em ociosidade enquanto uma tarefa ainda está
aguardando algum resultado de I/O, por exemplo. Ao invés de ficar
“bloqueado” aguardando, ele alterna de tarefa, inicia outros trabalhos
e volta nas outras tarefas em um tempo futuro quando elas estiverem
prontas. Fazendo uma analogia, vamos supor que você tem uma
tarefa que precisa fazer duas requisições na internet, o seu código
assíncrono vai lidar dessa forma:

“Faça essa primeira requisição, mas não vou ficar aqui esperando o Curta nossa
resultado, me avise quando tudo estiver pronto. Enquanto isso, deixa eu
executar a segunda requisição aqui.”

Enquanto no código síncrono seria:

“Faça essa primeira requisição. Eu terei que ficar esperando essa


resposta, pois necessito dela para continuar o meu fluxo de trabalho. [
… algum tempo depois …] Obrigado pela resposta, agora, por gentileza,
execute essa segunda requisição? Ficarei aqui aguardando o resultado
dela. [… algum tempo depois …] Obrigado pela resposta. Agora posso
concluir meu trabalho.”

Se você desenvolve um código síncrono para resolver uma operação


matemática e porta esse código para um modelo assíncrono, você vai
notar que ambos serão executados praticamente no mesmo tempo,
sem nenhum levar vantagem sobre o outro. Agora, a história muda
completamente se o seu problema precisa realizar alguma operação
I/O (que naturalmente é bloqueante) ou quando ele precisa aguardar
algum tempo por alguma coisa, nesse tipo de caso, o modelo
assíncrono leva muita vantagem, como mostra esse diagrama:
(https://www.treinaweb.com.br/blog/)
Acesse A Treinaweb (Https://Www.treinaweb.com.br)
(https://www.facebook.com/TreinaWeb/) (https://youtube.com.br/treinaweb)

Ferramentas Para Devs (Https://Www.treinaweb.com.br/Ferramentas-Para-Desenvolvedores/)


(https://instagram.com/treinaweb) (https://twitter.com/treinaweb)

Conheça Nossos Cursos (Https://Www.treinaweb.com.br/Cursos-Online)

Veja que nesse diagrama as tarefas alternam entre si, o modelo


Curta nossa
assíncrono tenta sempre evitar ociosidade/espera/bloqueio. Ele só fica
bloqueado/aguardando quando nenhuma tarefa pode fazer nenhum
progresso, aí ele precisa receber alguma chamada para voltar à sua
operação.

A abordagem assíncrona não é a solução para todos os problemas,


mas em comparação com o modelo síncrono, ela performa melhor
principalmente nos seguintes cenários:

• Quando o programa contém tarefas que fazem uso intensivo de


I/O;

• Quando o programa contém tarefas independentes, ou seja,


quando umas não precisam esperar pelas outras para realizar
seus trabalhos (e essas passam por algum estado de progresso
em suas atividades).

Quando não faz tanto sentido:

• Uma aplicação que faz um uso intensivo da CPU em que as


operações são dependentes, ou seja, uma precisa ser finalizada
para que a outra entre em cena;

• Uma aplicação que realiza grandes operações de I/O mas que o


uso da aplicação em si é infrequente e não há necessidade de
escalar;

Levando para exemplos do “mundo real” você vai ver com frequência o
uso de programação assíncrona para:

• Uma API em que o usuário faz uma requisição e precisa de uma


resposta rápida sem que precise esperar alguma operação ser
finalizada (essa operação pode continuar rodando lá no servidor
enquanto o usuário já obteve a resposta dele). Nesse sentido, a
interface do usuário não fica congelada esperando uma
resposta de uma operação que ele não precisa esperar por ela.
• Data Streaming (dá pra construir, por exemplo, até um servidor
(https://www.treinaweb.com.br/blog/)
Acesse A Treinaweb (Https://Www.treinaweb.com.br)
de streaming de vídeo);
(https://www.facebook.com/TreinaWeb/) (https://youtube.com.br/treinaweb)

• Aplicação de monitoramento;
Ferramentas Para Devs (Https://Www.treinaweb.com.br/Ferramentas-Para-Desenvolvedores/)
(https://instagram.com/treinaweb) (https://twitter.com/treinaweb)
• Criação de chats;
Conheça Nossos Cursos (Https://Www.treinaweb.com.br/Cursos-Online)
• Etc;

Apesar de termos dado exemplos clássicos aqui, é perfeitamente


possível integrar código assíncrono numa aplicação tradicional (de
abordagem síncrona) se você perceber que em determinado
momento requisições externas precisam ser feitas ou alguma
operação importante que envolva I/O, você pode estudar a
possibilidade de implementar um código assíncrono nessa parte para
obter o benefício da não ociosidade e melhorar o tempo de resposta Curta nossa
do seu usuário. Não existem “regras estritas” aqui, você vai precisar
avaliar caso a caso e decidir o que achar melhor. Mas, certamente, é
mais comum ver scripts que rodam em linha de comando (CLI)
utilizarem a abordagem assíncrona.

PHP Assíncrono
O PHP não dispõe (mas há a intenção de se implementar isso em
algum momento da versão 8 do PHP) de mecanismos nativos para
lidar com código assíncrono, diferente do JavaScript e C#, por
exemplo. Por isso bibliotecas como Amp (https://amphp.org/) e
ReactPHP (https://reactphp.org/) se tornaram relevantes, pois elas
abstraem isso. Nesse artigo introdutório, usaremos os componentes do
ReactPHP.

O ReactPHP é baseado no padrão Reactor


(https://en.wikipedia.org/wiki/Reactor_pattern) (o mesmo usado
pelo NodeJS) que é uma implementação de uma arquitetura orientada
a eventos (event-driven). A ideia é permitir que iniciemos múltiplas
operações I/O sem que precisemos esperar pela finalização delas (não
bloqueante). Ao invés disso, somos notificados quando algo
importante acontecer e reagimos a esse evento com um callback (se
você programa em JavaScript certamente já está familiarizado com
isso).

O ReactPHP possui uma série de componentes independentes e o


principal deles, que é o seu core é o EventLoop
(https://github.com/reactphp/event-loop), ele é a base para o
funcionamento de todos os outros componentes que o ReactPHP
disponibiliza. O componente EventLoop é uma implementação padrão
Reactor.
O Event Loop é basicamente um while infinito que faz o papel de ser o
(https://www.treinaweb.com.br/blog/)
Acesse A Treinaweb (Https://Www.treinaweb.com.br)
Scheduler das operações. Ele sequencialmente
(https://www.facebook.com/TreinaWeb/) processa a fila de
(https://youtube.com.br/treinaweb)
eventos e cuida da execução dos callbacks. Ele é o único código sendo
executado Ferramentas Paranenhum
sincronamente, Devs (Https://Www.treinaweb.com.br/Ferramentas-Para-Desenvolvedores/)
outro código é executado em
(https://instagram.com/treinaweb) (https://twitter.com/treinaweb)
paralelo. E, como já dissemos anteriormente, ele roda em uma única
thread. O fato do seu Conheça Nossos
processador Cursos
ter 16 (Https://Www.treinaweb.com.br/Cursos-Online)
núcleos ou 1, em nada vai
interferir, a execução do Event Loop continuará sendo single-thread. A
ideia por trás do ReactPHP é fazer um bom uso do tempo da CPU (sem
cair na ociosidade com as operações de I/O) e não exatamente em
paralelizar processos (o que demandaria diversos outros problemas de
comunicação, troca de estados, trocas de contexto por parte do
sistema operacional além, claro, de recursos de hardware).

O funcionamento é mais ou menos assim:


Curta nossa
• Você registra um evento;

• Você passa a “ouví-lo” (listening);

• Quando esse evento é disparado, você reage a ele via um


handler e executa algum código.

Diagrama simplificado de funcionamento de um Event Loop:

ReactPHP
O ReactPHP possui quatro implementações possíveis de Event Loop e
ele por padrão escolhe qual usar a partir da análise das extensões
instaladas no seu ambiente PHP.

As implementações são:

• StreamSelectLoop – Essa implementação funciona nativamente


no PHP sem precisar de nenhuma extensão específica, ela
executa chamadas de sistema select que resolvem a
implementação do event loop, mesmo que não na performance
das opções que serão mostradas abaixo.

• LibEventLoop – Essa opção usa a extensão libevent do repositório


pecl.
• LibEvLoop – Usa a extensão libev. Funciona de forma similar à
(https://www.treinaweb.com.br/blog/)
Acesse A Treinaweb (Https://Www.treinaweb.com.br)
libevent citada acima.
(https://www.facebook.com/TreinaWeb/) (https://youtube.com.br/treinaweb)

• ExtEventLoop – Usa a extensão event. Funciona de forma similar


Ferramentas Para Devs (Https://Www.treinaweb.com.br/Ferramentas-Para-Desenvolvedores/)
(https://instagram.com/treinaweb) (https://twitter.com/treinaweb)
à libevent citada anteriormente. Essa é a minha extensão de
escolha, por ser a mais atualizada e um dos desenvolvedores
Conheça Nossos Cursos (Https://Www.treinaweb.com.br/Cursos-Online)
dela também trabalha no core do PHP. Você pode ver mais
detalhes sobre ela clicando aqui
(https://pecl.php.net/package/event).

Mas, calma lá! Não é escopo nosso, por enquanto, se preocupar com
tudo isso. Se você vai desenvolver uma aplicação para produção que
vai usar ReactPHP, ótimo, eu lhe recomendaria muitíssimamente
instalar a extensão event. Mas, para o nosso objetivo didático, vamos
deixar que o próprio ReactPHP escolha a melhor implementação pra Curta nossa
gente, baseando-se no que temos instalado em nosso ambiente. Se
não tivermos nenhuma das três últimas extensões, ele vai usar a
primeira implementação, a **StreamSelectLoop **(standalone).

Ele possui uma factory que decide qual das implementações acima
será usada:

$loop = React\EventLoop\Factory::create();

As soluções escritas usando o ReactPHP não dependem de nada


específico de nenhuma das implementações acima, ou seja, não
importa qual a implementação será usada, o ReactPHP se comportará
da mesma maneira, as interfaces são as mesmas para todas. Isso nos
dá a liberdade de não nos preocuparmos em instalar uma extensão
para desenvolvermos alguns testes.

Timers
Timer são úteis para executar um determinado código em um
momento futuro. Funcionam da mesma forma que setTimeout() and
setInterval() do JavaScript.

Por exemplo, o Event Loop dispõe do método addPeriodicTimer() que


faz com que o callback informado seja executado repetidamente a
cada determinado intervalo de tempo.

Vamos criar o nosso primeiro exemplo? Tudo o que você precisa fazer é
criar um diretório no local onde normalmente você escreve suas
aplicações. Dentro dessa pasta, crie um arquivo composer.json com o
seguinte conteúdo:
{
(https://www.treinaweb.com.br/blog/)
Acesse A Treinaweb (Https://Www.treinaweb.com.br)
"require": {
(https://www.facebook.com/TreinaWeb/) (https://youtube.com.br/treinaweb)
"react/event-loop": "^1.1"
}
} Ferramentas Para Devs (Https://Www.treinaweb.com.br/Ferramentas-Para-Desenvolvedores/)
(https://instagram.com/treinaweb) (https://twitter.com/treinaweb)

Pelo terminal, acesse Conheça Nossos


esse diretório Cursos (Https://Www.treinaweb.com.br/Cursos-Online)
e execute:

$ composer install

Por fim, no mesmo diretório, crie um arquivo index.php com o seguinte


conteúdo:

<?php

require './vendor/autoload.php'; Curta nossa


$loop = React\EventLoop\Factory::create();

$loop->addPeriodicTimer(1, static function () {


static $count;

if (null === $count) {


$count = 0;
}

echo $count++ . PHP_EOL;


});

$loop->run();

// Output:

// 0
// 1
// 2
// 3
// 4
// 5
// ...

Para executar o exemplo:

$ php index.php

E você verá o resultado no seu terminal. A cada um segundo o callback


(a função anônima que definimos no segundo argumento de
addPeriodicTimer() é executada).

Outro método é o addTimer() :


<?php
(https://www.treinaweb.com.br/blog/)
Acesse A Treinaweb (Https://Www.treinaweb.com.br)
(https://www.facebook.com/TreinaWeb/) (https://youtube.com.br/treinaweb)
require './vendor/autoload.php';

Ferramentas Para Devs (Https://Www.treinaweb.com.br/Ferramentas-Para-Desenvolvedores/)


$loop = React\EventLoop\Factory::create();
(https://instagram.com/treinaweb) (https://twitter.com/treinaweb)
$loop->addTimer(2, static function () {
echo 'World'; Conheça Nossos Cursos (Https://Www.treinaweb.com.br/Cursos-Online)
});

echo 'Hello ';


$loop->run();

// Output: Hello World

Nesse caso, o callback será executado uma única vez, num tempo
futuro (em dois segundos).

Esse exemplo é, de certa forma, parecido com esse, escrito em


Curta nossa
JavasCript:

setTimeout(function () {
console.log('World');
}, 2);

console.log('Hello ');

Ambos os exemplos mostram que não estão seguindo o fluxo síncrono


de execução, ademais, uma parte do código foi programada para ser
executada em outro momento e isso não bloqueou a linha de
execução.

Streams
A documentação do PHP define Streams como uma forma de
generalizar arquivo, rede e outras operações que compartilham um
conjunto comum de funções e usos. Em outras palavras, streams
representam coleções de dados que podem não estar completamente
disponíveis de imediato e também não possuem a limitação de ter que
caber na memória, isso faz com que streams sejam uma ferramenta
poderosa para lidar com grandes quantidades de dados que podem
ser obtidas por partes (chunks). Grande parte do que é feito no PHP é
sobre streams. Ao ler um arquivo, lidamos com streams. Ao retornar
um output para o cliente, lidamos com streams. Ao obter dados de
uma conexão TCP/IP, também estamos lidando com streams.

Temos três tipos de Streams:

• Readable – Esse tipo permite ler (apenas leitura) os dados de


uma fonte;
• Writable – Esse tipo permite escrever (apenas escrita) dados em
(https://www.treinaweb.com.br/blog/)
Acesse A Treinaweb (Https://Www.treinaweb.com.br)
uma fonte;
(https://www.facebook.com/TreinaWeb/) (https://youtube.com.br/treinaweb)

• Duplex (Readable e Writable ao mesmo tempo) – Esse tipo


Ferramentas Para Devs (Https://Www.treinaweb.com.br/Ferramentas-Para-Desenvolvedores/)
(https://instagram.com/treinaweb)
permite ler e/ou escrever (ambos)(https://twitter.com/treinaweb)
dados, como é o caso do
protocolo TCP/IP (full-duplex).
Conheça Nossos Cursos (Https://Www.treinaweb.com.br/Cursos-Online)

Por exemplo, vamos supor que você precise avaliar linha a linha um
arquivo de log que possui 1GB, se fizer assim:

$log = file_get_content("error.log")

O PHP tentará carregar o arquivo inteiro na memória (e enquanto não


for carregado, nada mais pode ser executado, bloqueante por
natureza), o que fatalmente acarretará em um erro e a execução do Curta nossa
script será interrompida.

Usando a interface Readable Resource Stream do ReactPHP atingimos


esse objetivo de forma não bloqueante, performática e com o mínimo
uso de memória.

Vamos testar isso na prática? Criaremos um arquivo (na raiz do


projeto) com os 10 milhões de números, um por linha, se você usa um
sistema baseado em Unix, consegue atingir esse objetivo executando:

$ awk 'BEGIN { n = 1; while (n < 10000000) print (n++) }' > numeros.txt

No arquivo index.php, execute:

$content = file_get_contents('numeros.txt');

echo 'Memória utilizada: ' . (memory_get_peak_usage(true)/1024/1024);

// Memória utilizada: 77.24

O PHP tentará alocar cerca de ~78MB na memória. Se você tentar


limitar o consumo de memória pelo script, terá um estouro:

<?php

ini_set('memory_limit', '12M');

$content = file_get_contents('numeros.txt');

// PHP Fatal error: Allowed memory size of 12582912 bytes exhausted (tried to allocate 78897112 bytes)

 

Agora vamos usar a classe ReadableResourceStrea do ReactPHP:


<?php
(https://www.treinaweb.com.br/blog/)
Acesse A Treinaweb (Https://Www.treinaweb.com.br)
(https://www.facebook.com/TreinaWeb/) (https://youtube.com.br/treinaweb)
require './vendor/autoload.php';

Ferramentas Para Devs (Https://Www.treinaweb.com.br/Ferramentas-Para-Desenvolvedores/)


use React\Stream\ReadableResourceStream;
(https://instagram.com/treinaweb) (https://twitter.com/treinaweb)
$loop = React\EventLoop\Factory::create();
Conheça Nossos Cursos (Https://Www.treinaweb.com.br/Cursos-Online)
$stream = new ReadableResourceStream(
fopen('numeros.txt', 'rb'), $loop
);

$stream->on('data', function ($chunk) {


// echo "$chunk\n";
});

$stream->on('end', function () {
echo 'Memória utilizada: ' . (memory_get_peak_usage(true)/1024/1024);
});

$loop->run(); Curta nossa


// Memória utilizada: 2

O pico de consumo de memória ficou em 2MB (assim que a


informação fica disponível no buffer, já a utilizamos, liberando-o).
Poderíamos processar aí um arquivo bem maior, de dezenas ou
centenas de gigabytes.

Veja que nesse exemplo implementamos dois eventos: data e end . No


data recebemos os chunks (partes) do arquivo que está sendo lido. Em

end executamos um callback quando o processo é finalizado.

Nesse exemplo usamos fopen() , função nativa do PHP (que trabalha


com streams), mas em uma aplicação verdadeiramente assíncrona,
ao invés disso, devemos usar o componente Filesystem
(https://github.com/reactphp/filesystem) do ReacPHP pois, se tiver
uma disputa na leitura do arquivo, a aplicação pode ficar congelada
(ler qualquer coisa do sistema de arquivos é bloqueante por natureza).
Com esse componente, teríamos algo como:
<?php
(https://www.treinaweb.com.br/blog/)
Acesse A Treinaweb (Https://Www.treinaweb.com.br)
(https://www.facebook.com/TreinaWeb/) (https://youtube.com.br/treinaweb)
require './vendor/autoload.php';

Ferramentas Para Devs (Https://Www.treinaweb.com.br/Ferramentas-Para-Desenvolvedores/)


use React\Filesystem\Filesystem;
(https://instagram.com/treinaweb) (https://twitter.com/treinaweb)
$loop = React\EventLoop\Factory::create();
Conheça Nossos Cursos (Https://Www.treinaweb.com.br/Cursos-Online)
$filesystem = Filesystem::create($loop);

$filesystem->file('numeros.txt')->open('rb')->then(function($stream) {
$stream->on('data', function ($chunk) {
// echo "$chunk\n";
});

$stream->on('end', function () {
//
});
});

$loop->run();
Curta nossa

Ah, para rodar esse exemplo é necessário que você instale o


componente no seu projeto:

$ composer require react/filesystem

Se você já usou promises no JavaScript deve ter notado o método


then() ali em cima. O conceito é o mesmo. O método open() retorna

uma promise e no método then() executamos um callback quando


ela (a “promessa”) é cumprida.

Lembra do exemplo que citamos lá no começo do artigo sobre uma


tarefa que verifica se os links de um site estão online? Pois bem, ela
poderia ser implementada usando a library reactphp-buzz
(https://github.com/clue/reactphp-buzz), pois ela abstrai todo o
essencial para se fazer requisições HTTP assíncronas.

Um protótipo de como isso poderia ser implementado de forma


síncrona:
<?php
(https://www.treinaweb.com.br/blog/)
Acesse A Treinaweb (Https://Www.treinaweb.com.br)
(https://www.facebook.com/TreinaWeb/) (https://youtube.com.br/treinaweb)
$time_start = microtime(true);

Ferramentas Para Devs


function urlsFromHtml(string (Https://Www.treinaweb.com.br/Ferramentas-Para-Desenvolvedores/)
$html) : array
(https://instagram.com/treinaweb)
{ (https://twitter.com/treinaweb)
$dom = new DOMDocument();
Conheça Nossos Cursos (Https://Www.treinaweb.com.br/Cursos-Online)
libxml_use_internal_errors(true);
$dom->loadHTML($html);
libxml_use_internal_errors(false);

$urls = [];

foreach ($dom->getElementsByTagName('a') as $node) {


$urls[] = $node->getAttribute('href');
}

return $urls;
}
Curta nossa
function getUrlStatusCode(string $url) : int
{
$curl = curl_init();

curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);


curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'HEAD');
curl_setopt($curl, CURLOPT_HEADER, 1);
curl_setopt($curl, CURLOPT_NOBODY, true);
curl_setopt($curl, CURLOPT_URL, $url);

curl_exec($curl);
$code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);

return $code;
}

function getUrlContent(string $url)


{
$curl = curl_init($url);

curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);


$html = curl_exec($curl);
curl_close($curl);

return $html;
}

$urls = urlsFromHtml(
getUrlContent('https://www.globo.com')
);

foreach ($urls as $url) {


$status = getUrlStatusCode($url) === 200 ? ' [online]' : ' [offline]';

echo "{$url} -> {$status} \n";


}

echo 'Tempo total de execução: ' . round(microtime(true) - $time_start);

 

Dessa forma demora cerca de 150 segundos para “pingar” todas as


URLS extraídas. Agora, a mesma implementação usando ReactPHP e e
a library reactphp-buzz:

Primeiro instale a dependência dela no projeto:


$ composer require clue/buzz-react:^2.6
(https://www.treinaweb.com.br/blog/)
Acesse A Treinaweb (Https://Www.treinaweb.com.br)
(https://www.facebook.com/TreinaWeb/) (https://youtube.com.br/treinaweb)

<?php Ferramentas Para Devs (Https://Www.treinaweb.com.br/Ferramentas-Para-Desenvolvedores/)


(https://instagram.com/treinaweb) (https://twitter.com/treinaweb)
require './vendor/autoload.php';

Conheça Nossos Cursos (Https://Www.treinaweb.com.br/Cursos-Online)


use Psr\Http\Message\ResponseInterface;

$loop = React\EventLoop\Factory::create();
$browser = new Clue\React\Buzz\Browser($loop);

function urlsFromHtml(string $html) : array


{
$dom = new DOMDocument();

libxml_use_internal_errors(true);
$dom->loadHTML($html);
libxml_use_internal_errors(false);
Curta nossa
$urls = [];

foreach ($dom->getElementsByTagName('a') as $node) {


$urls[] = $node->getAttribute('href');
}

return $urls;
}

$browser->get('https://www.globo.com')->then(function (ResponseInterface $response


$urls = urlsFromHtml($response->getBody());
foreach ($urls as $url) {
$browser->head($url)->then(function (ResponseInterface $response)
$status = $response->getStatusCode() === 200 ? ' [online]' : ' [offline]'

echo "{$url} -> {$status} \n";


});
}
});

$time_start = microtime(true);

$loop->run();

echo 'Tempo total de execução: ' . round(microtime(true) - $time_start);

 

Já de forma assíncrona custou apenas 18 segundos. Lembrando que


esse é apenas um exemplo para comparar a diferença entre os dois
modelos.

Recomendação de leitura:
Promises no ReactPHP
O outro artigo da série foi publicado, ele trata o uso de Promises com o
ReactPHP (https://www.treinaweb.com.br/blog/promises-no-
reactphp/). Você pode acessá-lo clicando aqui
(https://www.treinaweb.com.br/blog/promises-no-reactphp/).
Concluindo (https://www.treinaweb.com.br/blog/)
Acesse A Treinaweb (Https://Www.treinaweb.com.br)
(https://www.facebook.com/TreinaWeb/) (https://youtube.com.br/treinaweb)

Esse foi um artigo introdutório sobre programação assíncrona e


Ferramentas Para Devs (Https://Www.treinaweb.com.br/Ferramentas-Para-Desenvolvedores/)
ReactPHP. Deu pra notar como é poderoso
(https://instagram.com/treinaweb) manipular streams, muitas
(https://twitter.com/treinaweb)
possibilidades são abertas. Tem muito mais o que podemos explorar
Conheça Nossos Cursos (Https://Www.treinaweb.com.br/Cursos-Online)
como Ticks, Promises, trabalhar com sistema de arquivos, trabalhar
com websockets, usar funcionalidades do sistema operacional através
de processos filhos, entre muitas outras coisas. Existem diversos
projetos opensource desenvolvidos em cima do ReactPHP para atingir
objetivos diversos, conforme você pode ver no site oficial
(https://reactphp.org/).

Deixe seu comentário


Curta nossa
2 comentários Classificar por Principais

Adicione um comentário...

Thyago Ghelere
Cara... Que introdução f***!!!

Muito bom
Curtir · Responder · 1 · 1 sem

Eduardo Zatti
Ótimo Artigo!
Curtir · Responder · 1 · 10 sem

Plugin de comentários do Facebook

# ASSÍNCRONO (HTTPS://WWW.TREINAWEB.COM.BR/BLOG/TAG/ASSINCRONO/)

# EVENT LOOP (HTTPS://WWW.TREINAWEB.COM.BR/BLOG/TAG/EVENT-LOOP/)

# NODEJS (HTTPS://WWW.TREINAWEB.COM.BR/BLOG/TAG/NODEJS/)

# REACTPHP (HTTPS://WWW.TREINAWEB.COM.BR/BLOG/TAG/REACTPHP/)

# SÍNCRONO (HTTPS://WWW.TREINAWEB.COM.BR/BLOG/TAG/SINCRONO/)

SHARE

Como criar um briefing Como conseguir o


matador primeiro emprego na
Previous post área de TI?
(https://www.treinaweb.com.br/blog/como- Next post
criar-um-briefing- (https://www.treinaweb.com.br/blog/como-
matador/) conseguir-o-primeiro-
emprego-na-area-de-
ti/)
Kennedy Tedesco
(https://www.treinaweb.com.br/blog/)
Acesse A Treinaweb (Https://Www.treinaweb.com.br)
(https://www.treinaweb.com.br/blog/author/kennedy-
(https://www.facebook.com/TreinaWeb/) (https://youtube.com.br/treinaweb)
tedesco/)
Ferramentas
HeadPara Devs (Https://Www.treinaweb.com.br/Ferramentas-Para-Desenvolvedores/)
de desenvolvimento. Vasta experiência em
(https://instagram.com/treinaweb) (https://twitter.com/treinaweb)
desenvolvimento Web com foco em PHP. Graduado
em Sistemas de Informação. Pós-graduando em
Conheça Nossos Cursos (Https://Www.treinaweb.com.br/Cursos-Online)
Arquitetura de Software Distribuído pela PUC Minas.
Zend Certified Engineer (ZCE) e Coffee Addicted
Person (CAP). @KennedyTedesco
(https://twitter.com/KennedyTedesco)

(https://github.com/KennedyTedesco)
(mailto:kennedy.tedesco@treinaweb.com.br)
(http://KennedyTedesco)

Related Articles
Curta nossa
PHP PHP
(HTTPS://WWW.TREINAWEB.COM.BR/BLOG/CATEGORIA/DESENVOLVIMENTO-
(HTTPS://WWW.TREINAWEB.COM.BR/BLOG/CATEGORIA/DESENVOLVIMENTO-
BACK-END/PHP/) BACK-END/PHP/)

(https://www.treinaweb.com.br/blog/foreach-
(https://www.treinaweb.com.br/blog/condicional-
no-php-aprenda-ler-arrays-e- if-else-no-php-aprenda-suas-
outras-estruturas/) caracteristicas/)

Foreach no PHP. Condicional IF Else no


Aprenda ler arrays e PHP. Aprenda suas
outras estruturas! características!
(https://www.treinaweb.com.br/blog/foreach-
(https://www.treinaweb.com.br/blog/condicional-
no-php-aprenda-ler- if-else-no-php-
arrays-e-outras- aprenda-suas-
estruturas/) caracteristicas/)

Elton Fonseca Elton Fonseca


(https://www.treinaweb.com.br/blog/author/elton-
(https://www.treinaweb.com.br/blog/author/elton-
fonseca/) fonseca/)
16 De Junho De 2020 12 De Junho De 2020

Arrays no PHP: Aprenda


como declarar e
acessar!
(https://www.treinaweb.com.br/blog/arrays-
no-php-aprenda-
como-declarar-e-
(https://www.treinaweb.com.br/blog/principais-
ides-para-desenvolvimento- acessar/)
php/)
Principais IDEs para
(https://www.treinaweb.com.br/blog/)
Acesse Elton Fonseca (Https://Www.treinaweb.com.br)
A Treinaweb
desenvolvimento PHP
(https://www.facebook.com/TreinaWeb/) (https://youtube.com.br/treinaweb)
(https://www.treinaweb.com.br/blog/author/elton-
(https://www.treinaweb.com.br/blog/principais-
fonseca/)
Ferramentas Para Devs (Https://Www.treinaweb.com.br/Ferramentas-Para-Desenvolvedores/)
ides-para-
(https://instagram.com/treinaweb) 7 De Maio De 2020
(https://twitter.com/treinaweb)
desenvolvimento-
Conheça Nossos Cursos (Https://Www.treinaweb.com.br/Cursos-Online)
php/)

Ana Paula de Andrade


(https://www.treinaweb.com.br/blog/author/ana-
paula-andrade/)
9 De Junho De 2020

Curta nossa
(https://www.treinaweb.com.br/blog/)
Acesse A Treinaweb (Https://Www.treinaweb.com.br)
(https://www.facebook.com/TreinaWeb/) (https://youtube.com.br/treinaweb)

Ferramentas Para Devs (Https://Www.treinaweb.com.br/Ferramentas-Para-Desenvolvedores/)


(https://instagram.com/treinaweb) (https://twitter.com/treinaweb)

Conheça Nossos Cursos (Https://Www.treinaweb.com.br/Cursos-Online)

Curta nossa
(https://www.treinaweb.com.br/blog/)
Acesse A Treinaweb (Https://Www.treinaweb.com.br)
(https://www.facebook.com/TreinaWeb/) (https://youtube.com.br/treinaweb)

Ferramentas Para Devs (Https://Www.treinaweb.com.br/Ferramentas-Para-Desenvolvedores/)


(https://instagram.com/treinaweb) (https://twitter.com/treinaweb)

Conheça Nossos Cursos (Https://Www.treinaweb.com.br/Cursos-Online)

Curta nossa
(https://www.treinaweb.com.br/blog/)
Acesse A Treinaweb (Https://Www.treinaweb.com.br)
(https://www.facebook.com/TreinaWeb/) (https://youtube.com.br/treinaweb)

Ferramentas Para Devs (Https://Www.treinaweb.com.br/Ferramentas-Para-Desenvolvedores/)


(https://instagram.com/treinaweb) (https://twitter.com/treinaweb)

Conheça Nossos Cursos (Https://Www.treinaweb.com.br/Cursos-Online)

Curta nossa
(https://www.treinaweb.com.br/blog/)
Acesse A Treinaweb (Https://Www.treinaweb.com.br)
(https://www.facebook.com/TreinaWeb/) (https://youtube.com.br/treinaweb)

Ferramentas Para Devs (Https://Www.treinaweb.com.br/Ferramentas-Para-Desenvolvedores/)


(https://instagram.com/treinaweb) (https://twitter.com/treinaweb)

Conheça Nossos Cursos (Https://Www.treinaweb.com.br/Cursos-Online)

Curta nossa
(https://www.treinaweb.com.br/blog/)
Acesse A Treinaweb (Https://Www.treinaweb.com.br)
(https://www.facebook.com/TreinaWeb/) (https://youtube.com.br/treinaweb)

Ferramentas Para Devs (Https://Www.treinaweb.com.br/Ferramentas-Para-Desenvolvedores/)


(https://instagram.com/treinaweb) (https://twitter.com/treinaweb)

Conheça Nossos Cursos (Https://Www.treinaweb.com.br/Cursos-Online)

Curta nossa
(https://www.treinaweb.com.br/blog/)
Acesse A Treinaweb (Https://Www.treinaweb.com.br)
(https://www.facebook.com/TreinaWeb/) (https://youtube.com.br/treinaweb)

Ferramentas Para Devs (Https://Www.treinaweb.com.br/Ferramentas-Para-Desenvolvedores/)


(https://instagram.com/treinaweb) (https://twitter.com/treinaweb)

Conheça Nossos Cursos (Https://Www.treinaweb.com.br/Cursos-Online)

Curta nossa
(https://www.treinaweb.com.br/blog/)
Acesse A Treinaweb (Https://Www.treinaweb.com.br)
(https://www.facebook.com/TreinaWeb/) (https://youtube.com.br/treinaweb)

Ferramentas Para Devs (Https://Www.treinaweb.com.br/Ferramentas-Para-Desenvolvedores/)


(https://instagram.com/treinaweb) (https://twitter.com/treinaweb)

Conheça Nossos Cursos (Https://Www.treinaweb.com.br/Cursos-Online)

Curta nossa
(https://www.treinaweb.com.br/blog/)
Acesse A Treinaweb (Https://Www.treinaweb.com.br)
(https://www.facebook.com/TreinaWeb/) (https://youtube.com.br/treinaweb)

Ferramentas Para Devs (Https://Www.treinaweb.com.br/Ferramentas-Para-Desenvolvedores/)


(https://instagram.com/treinaweb) (https://twitter.com/treinaweb)

Conheça Nossos Cursos (Https://Www.treinaweb.com.br/Cursos-Online)

Curta nossa
(https://www.treinaweb.com.br/blog/)
Acesse A Treinaweb (Https://Www.treinaweb.com.br)
(https://www.facebook.com/TreinaWeb/) (https://youtube.com.br/treinaweb)

Ferramentas Para Devs (Https://Www.treinaweb.com.br/Ferramentas-Para-Desenvolvedores/)


(https://instagram.com/treinaweb) (https://twitter.com/treinaweb)

Conheça Nossos Cursos (Https://Www.treinaweb.com.br/Cursos-Online)

Curta nossa
(https://www.treinaweb.com.br/blog/)
Acesse A Treinaweb (Https://Www.treinaweb.com.br)
(https://www.facebook.com/TreinaWeb/) (https://youtube.com.br/treinaweb)

Ferramentas Para Devs (Https://Www.treinaweb.com.br/Ferramentas-Para-Desenvolvedores/)


(https://instagram.com/treinaweb) (https://twitter.com/treinaweb)

Conheça Nossos Cursos (Https://Www.treinaweb.com.br/Cursos-Online)

Curta nossa
Quem somos

A TreinaWeb é a única escola


Full Stack e DevOps do Brasil! Já
são 12 anos formando
desenvolvedores. Hoje,
contamos com mais 350
cursos e cerca de 4.000 horas
de conteúdo, formações e
cursos completos.

(https://www.instagram.com/treinaweb/?

hl=pt-

(https://www.facebook.com/TreinaWeb/)
(https://www.youtube.com/treinaweb)
br) (https://www.linkedin.com/company/treinaweb)
(https://br.pinterest.com/treinaweb/)

(https://twitter.com/treinaweb)
(https://treinaweb.com.br/blog/feed)

Categorias de Artigos

Bancos de Dados
(https://www.treinaweb.com.br/blog/categoria/bancos-
de-dados/)
Carreira
(https://www.treinaweb.com.br/blog/categoria/carreira/)
(https://www.treinaweb.com.br/blog/)
Acesse A Treinaweb (Https://Www.treinaweb.com.br)
(https://www.facebook.com/TreinaWeb/) (https://youtube.com.br/treinaweb)
CMS’s e E-commerce
(https://www.treinaweb.com.br/blog/categoria/cmss-
Ferramentas Para Devs (Https://Www.treinaweb.com.br/Ferramentas-Para-Desenvolvedores/)
(https://instagram.com/treinaweb)e-e-commerce/)
(https://twitter.com/treinaweb)

Computação em nuvem
Conheça Nossos Cursos (Https://Www.treinaweb.com.br/Cursos-Online)
(https://www.treinaweb.com.br/blog/categoria/computacao-
em-nuvem/)

Desenvolvimento
(https://www.treinaweb.com.br/blog/categoria/desenvolvimento/)

Desenvolvimento Back-end
(https://www.treinaweb.com.br/blog/categoria/desenvolvimento-
back-end/)

Desenvolvimento de Jogos
(https://www.treinaweb.com.br/blog/categoria/desenvolvimento-
de-jogos/) Curta nossa
Desenvolvimento Front-end
(https://www.treinaweb.com.br/blog/categoria/desenvolvimento-
front-end/)

Desenvolvimento Mobile
(https://www.treinaweb.com.br/blog/categoria/desenvolvimento-
mobile/)

Design
(https://www.treinaweb.com.br/blog/categoria/design/)

Entrevistas
(https://www.treinaweb.com.br/blog/categoria/entrevistas/)

Governança
(https://www.treinaweb.com.br/blog/categoria/governanca/)

Infraestrutura e Sistemas Operacionais


(https://www.treinaweb.com.br/blog/categoria/infraestrutura-
e-sistemas-operacionais/)

Marketing Digital
(https://www.treinaweb.com.br/blog/categoria/marketing-
digital/)

Tecnologia
(https://www.treinaweb.com.br/blog/categoria/tecnologia/)

A Treinaweb

Vantagens de estudar no Treinaweb


(https://www.treinaweb.com.br/vantagens-de-estudar-no-
treinaweb?
utm_source=blog&utm_medium=link&utm_campaign=tw-
blog)

O que os nossos alunos dizem?


(https://www.treinaweb.com.br/depoimentos?
utm_source=blog&utm_medium=link&utm_campaign=tw-
blog)

Quanto Custa?
(https://www.treinaweb.com.br/planos)
(https://www.treinaweb.com.br/blog/)
Nossos Acesse A Treinaweb (Https://Www.treinaweb.com.br)
Cursos
(https://www.facebook.com/TreinaWeb/)
(https://www.treinaweb.com.br/cursos- (https://youtube.com.br/treinaweb)
online)
Ferramentas Para Devs (Https://Www.treinaweb.com.br/Ferramentas-Para-Desenvolvedores/)
(https://instagram.com/treinaweb)
Formações(https://twitter.com/treinaweb)
(https://www.treinaweb.com.br/formacoes)

Conheça Nossos Cursos (Https://Www.treinaweb.com.br/Cursos-Online)


Cursos para empresas
(https://www.treinaweb.com.br/contato/empresa?
utm_source=blog&utm_medium=link&utm_campaign=tw-
blog)

Ferramentas para desenvolvedores


(https://www.treinaweb.com.br/ferramentas-para-
desenvolvedores?
utm_source=blog&utm_medium=link&utm_campaign=tw-
blog)

Sugira um novo artigo


(https://www.treinaweb.com.br/contato? Curta nossa
utm_source=blog&utm_medium=link&utm_campaign=tw-
blog)

Trabalhe Conosco (https://www.treinaweb.com.br/trabalhe-


conosco?
utm_source=blog&utm_medium=link&utm_campaign=tw-
blog)

Contato (https://www.treinaweb.com.br/contato?
utm_source=blog&utm_medium=link&utm_campaign=tw-
blog)

© 2004 - 2019 TreinaWeb Tecnologia LTDA - CNPJ: 06.156.637/0001-58 Av. Paulista, 1765, Conj 71 e 72 - Bela Vista -
São Paulo - SP - 01311-200