Introdução à Programação Assíncrona em PHP
Tradicionalmente, o PHP é uma linguagem síncrona: cada requisição é executada sequencialmente, bloqueando a execução até a conclusão de uma operação de entrada-saída. No entanto, com o aumento das exigências de desempenho das aplicações web, a programação assíncrona em PHP tornou-se uma necessidade. Ela permite processar milhares de conexões simultâneas, executar tarefas paralelas e utilizar eficientemente os recursos do sistema.
Neste guia, abordaremos abordagens práticas para programação assíncrona em PHP: desde conceitos básicos até exemplos reais usando bibliotecas modernas e recursos nativos do PHP 8.1+.
Fundamentos da Assincronia: Event Loop e Entrada-Saída Não Bloqueante
Na base de qualquer aplicação assíncrona está o Event Loop (ciclo de eventos). É um loop infinito que verifica a existência de novos eventos (requisições, dados do banco de dados, arquivos) e distribui seu processamento sem bloquear o fluxo principal.
O código síncrono funciona assim:
<?php// Operação bloqueante - o programa espera 5 segundossleep(5);echo "Passaram-se 5 segundos";// O próximo código será executado apenas após o sleepecho "Esta mensagem aparecerá após 5 segundos";?>Abordagem assíncrona usando ReactPHP:
<?phprequire 'vendor/autoload.php';
use React\\EventLoop\\Factory;use React\\Promise\\Promise;
$loop = Factory::create();
// Timer não bloqueante$loop->addTimer(5, function () { echo "Passaram-se 5 segundos";});
echo "Esta mensagem aparecerá imediatamente";$loop->run();?>Na versão assíncrona, o código não bloqueia: a mensagem é exibida imediatamente, enquanto o timer é acionado em segundo plano.
Guia Prático: do Simples ao Complexo
1. Uso de Fiber (PHP 8.1+)
Fiber é um mecanismo nativo de corrotinas introduzido no PHP 8.1. Ele permite pausar a execução de uma função e retomá-la posteriormente sem bloquear o fluxo.
Exemplo de execução paralela de tarefas com Fiber:
<?phpfunction fetchData(string $url): Fiber{ return new Fiber(function () use ($url) { // Simulação de requisição HTTP $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 5); // Pausa o Fiber Fiber::suspend(curl_exec($ch)); curl_close($ch); });}
// Cria vários Fibers$fiber1 = fetchData('https://api.example.com/data1');$fiber2 = fetchData('https://api.example.com/data2');
// Inicia os Fibers$result1 = $fiber1->start();$result2 = $fiber2->start();
// Retoma a execução$result1 = $fiber1->resume();$result2 = $fiber2->resume();
echo "Resultado 1: " . $result1 . "";echo "Resultado 2: " . $result2 . "";?>2. Trabalho Assíncrono com Banco de Dados via Amp
Amp é uma biblioteca poderosa para programação assíncrona. Vejamos um exemplo de conexão assíncrona ao MySQL:
<?phprequire 'vendor/autoload.php';
use Amp\\Loop;use Amp\\Mysql\\ConnectionConfig;use Amp\\Mysql\\Pool;
Loop::run(function () { $config = ConnectionConfig::fromString( "host=localhost user=root password=secret db=test" ); $pool = new Pool($config); // Consulta assíncrona - não bloqueia a execução $promise1 = $pool->query("SELECT SLEEP(2)"); $promise2 = $pool->query("SELECT 1 + 1 AS result"); // Ambas as consultas são executadas em paralelo $result1 = yield $promise1; $result2 = yield $promise2; foreach ($result2 as $row) { echo "Resultado: " . $row['result'] . ""; } $pool->close();});?>3. Criação de um Servidor HTTP Assíncrono com ReactPHP
Completo