0Pricing
PHP Academy · Aula

Fibers do PHP 8.1

Pause e retome a execução com Fibers nativas.

Fibers do PHP 8.1 é uma aula grátis de PHP Academy no CoddyKit. Esta é a aula 2 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de PHP Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de PHP Academy inclui 4 aulas no total.

O que as fibras oferecem

O PHP 8.1 adicionou as fibras: uma primitiva do núcleo que permite pausar uma pilha de chamadas em execução e retomá-la mais tarde, a partir de um lugar completamente diferente. Uma fibra é uma pilha completa e independente que pode ser suspensa em um ponto arbitrário e continuar sem desfazer a pilha. Essa é a peça que faltava para que as bibliotecas substituíssem cadeias de promessas por um await com aparência síncrona — o mecanismo por trás das APIs modernas do ReactPHP e do Amp.

Sua primeira fibra

Crie uma fibra com uma função de retorno, inicie-a com start() e permita que ela se suspenda com suspend(). O controle retorna ao chamador no ponto de suspensão; resume() continua exatamente desse ponto.

<?php
$fiber = new Fiber(function (): void {
    echo "A: inside fiber\n";
    $received = Fiber::suspend('paused');
    echo "C: resumed with '$received'\n";
});

$value = $fiber->start();          // prints A, returns 'paused'
echo "B: fiber suspended, got '$value'\n";
$fiber->resume('hello');           // prints C
echo "D: fiber done\n";

Os quatro métodos principais

A API é pequena:

  • $fiber->start(...$args) — inicia a execução; retorna o primeiro valor de suspensão.
  • Fiber::suspend($value) — pausa a fibra atual, entregando $value a quem a retoma.
  • $fiber->resume($value) — continua a execução; $value torna-se o retorno de suspend().
  • $fiber->getReturn() — retorna o valor devolvido pela função de retorno após o término.

Os valores fluem nas duas direções através do limite de suspensão.

Passagem bidirecional de valores

Uma fibra pode enviar uma solicitação e receber uma resposta de volta — esse é o mecanismo central pelo qual um loop de eventos fornece resultados de E/S às tarefas suspensas.

<?php
$fiber = new Fiber(function (): int {
    $a = Fiber::suspend('need first number');
    $b = Fiber::suspend('need second number');
    return $a + $b;
});

$fiber->start();        // suspends: 'need first number'
$fiber->resume(10);     // a = 10, suspends: 'need second number'
$fiber->resume(32);     // b = 32, fiber returns
echo $fiber->getReturn(), PHP_EOL; // 42

Estado e introspecção de uma fibra

É possível consultar o ciclo de vida de uma fibra. Chamar resume() em uma fibra terminada lança FiberError, portanto proteja-se com estas verificações ao criar um agendador.

<?php
$fiber = new Fiber(function () { Fiber::suspend(); });
var_dump($fiber->isStarted());     // false
$fiber->start();
var_dump($fiber->isStarted());     // true
var_dump($fiber->isSuspended());   // true
var_dump($fiber->isRunning());     // false (we're outside it)
$fiber->resume();
var_dump($fiber->isTerminated());  // true

Criando um pequeno agendador

Fibras mais uma fila equivalem a um agendador cooperativo. Cada tarefa se suspende para ceder o controle; o agendador alterna entre elas em ordem circular até que todas terminem. Essa é a estrutura básica presente em todo ambiente de execução assíncrono.

<?php
$tasks = [];
foreach (['X', 'Y', 'Z'] as $name) {
    $tasks[] = new Fiber(function () use ($name) {
        for ($i = 1; $i <= 2; $i++) {
            echo "$name step $i\n";
            Fiber::suspend();   // give others a turn
        }
    });
}
foreach ($tasks as $t) { $t->start(); }
while ($tasks) {
    foreach ($tasks as $k => $t) {
        if ($t->isTerminated()) { unset($tasks[$k]); continue; }
        $t->resume();
    }
}

Exceções através dos limites

throwInto() (chamado de throw() na API, como em $fiber->throw()) injeta uma exceção no ponto de suspensão — é assim que um loop informa uma operação de E/S com falha à tarefa que está aguardando. A exceção aparece exatamente onde a fibra foi pausada.

<?php
$fiber = new Fiber(function () {
    try {
        Fiber::suspend();
    } catch (RuntimeException $e) {
        echo 'caught: ' . $e->getMessage() . PHP_EOL;
    }
});
$fiber->start();
$fiber->throw(new RuntimeException('io failed')); // prints: caught: io failed

Fibras versus geradores

Os geradores (yield) também suspendem a execução — mas somente a função do topo. Para aguardar a partir de uma função auxiliar aninhada usando geradores, é necessário usar yield from em toda a pilha, marcando cada função. As fibras suspendem a pilha inteira a partir de qualquer profundidade, portanto uma chamada profundamente aninhada pode usar Fiber::suspend() sem que seus chamadores saibam. É por isso que await pode ser uma chamada de função comum, em vez de um yield.

<?php
function deep(): string {
    // No yield needed in the call chain — suspends the whole fiber
    return Fiber::suspend('awaiting from deep');
}
$f = new Fiber(fn() => print(deep() . PHP_EOL));
$f->start();
$f->resume('value injected at depth');

A restrição da suspensão

Há uma regra rígida: só é possível usar Fiber::suspend() dentro de uma fibra. Suspender a partir da linha de execução principal ou através de uma função de retorno no nível C que não ofereça suporte a fibras (alguns comparadores legados de usort, certas funções de retorno internas) lança FiberError: Cannot suspend outside of a fiber. As bibliotecas ocultam essa restrição garantindo que todo o código do usuário seja executado dentro de uma fibra controlada pelo loop.

<?php
try {
    Fiber::suspend(); // main thread — illegal
} catch (FiberError $e) {
    echo $e->getMessage(), PHP_EOL; // Cannot suspend outside of a fiber
}

Como as bibliotecas usam fibras

Raramente se escrevem fibras brutas no código da aplicação. Frameworks como o Amp v3 e o ReactPHP (por meio de fibras) encapsulam-nas: await($promise) chama internamente Fiber::suspend(), registra uma continuação no loop de eventos e retoma sua fibra quando a E/S é concluída. Seu código parece síncrono; o ambiente de execução gerencia a suspensão e o agendamento.

<?php
// Conceptual: what an await() helper does under the hood
function await(Promise $p): mixed {
    $fiber = Fiber::getCurrent() ?? throw new Error('await() outside fiber');
    $p->then(fn($v) => $fiber->resume($v),
             fn($e) => $fiber->throw($e));
    return Fiber::suspend(); // parked until the promise settles
}

Considerações sobre memória e ciclo de vida

Cada fibra aloca sua própria pilha, portanto criar centenas de milhares delas tem um custo de memória (embora sejam muito mais leves que as linhas de execução do OS). Uma fibra suspensa para sempre nunca é coletada pelo coletor de lixo se algo ainda fizer referência a ela — um vazamento sutil em servidores de longa duração. Além disso, se a função de retorno de uma fibra lançar uma exceção não capturada, ela será propagada para fora da chamada resume()/start(), portanto o agendador deve envolver as retomadas em blocos de tentativa e captura.

<?php
$fiber = new Fiber(function () {
    throw new RuntimeException('boom inside fiber');
});
try {
    $fiber->start(); // exception surfaces here, at the resumer
} catch (RuntimeException $e) {
    echo 'scheduler caught: ' . $e->getMessage() . PHP_EOL;
}

Verificação rápida

Qual é a principal vantagem das fibras em relação aos geradores para a programação assíncrona?

Recapitulação

As fibras são a primitiva de baixo nível para concorrência do PHP:

  • start(), Fiber::suspend(), resume(), getReturn() pausam e continuam uma pilha de chamadas completa, passando valores nas duas direções.
  • Os métodos de estado (isSuspended, isTerminated) e throw() permitem criar um agendador cooperativo e injetar erros de E/S.
  • Diferentemente dos geradores, uma fibra pode ser suspensa a partir de qualquer profundidade — possibilitando um await() transparente.
  • Só é possível suspender dentro de uma fibra; frameworks como Amp e ReactPHP encapsulam as fibras para que o código assíncrono seja lido como código síncrono.

Perguntas Frequentes

A aula “Fibers do PHP 8.1” é grátis?

Sim — o texto completo de “Fibers do PHP 8.1” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de PHP Academy, atualize para CoddyKit PRO. O curso de PHP Academy inclui 4 aulas no total.

O que vou aprender em “Fibers do PHP 8.1”?

Pause e retome a execução com Fibers nativas. Você pratica PHP Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar PHP Academy?

Nenhuma experiência prévia é necessária. PHP Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 2 de 4.

Quanto tempo leva a aula “Fibers do PHP 8.1”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de PHP Academy?

Sim. Cada aula de PHP Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. O modelo de concorrência do PHP
  2. Fibers do PHP 8.1
  3. Loops de eventos com ReactPHP
  4. Servidores de alto desempenho com Swoole
← Voltar para PHP Academy