0Pricing
PHP Academy · Lección

Fibers de PHP 8.1

Pause y reanude la ejecución mediante Fibers nativas.

Fibers de PHP 8.1 es una lección gratuita de PHP Academy en CoddyKit. Esta es la lección 2 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de PHP Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de PHP Academy incluye 4 lecciones en total.

Qué le ofrecen las Fibers

PHP 8.1 añadió las Fibers: una primitiva del núcleo que permite pausar una pila de llamadas en ejecución y reanudarla más tarde desde un lugar completamente diferente. Una Fiber es una pila completa e independiente que puede suspenderse en un punto arbitrario y continuar sin desenrollarse. Esta es la pieza que faltaba para que las bibliotecas sustituyeran las cadenas de promesas por un await con apariencia síncrona; es la base de las API modernas de ReactPHP y Amp.

Su primera Fiber

Cree una Fiber con un callback, iníciela con start() y permita que se suspenda con suspend(). El control vuelve a quien hizo la llamada en el punto de suspensión; resume() continúa exactamente desde ahí.

<?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";

Los cuatro métodos principales

La API es pequeña:

  • $fiber->start(...$args): inicia la ejecución y devuelve el primer valor de suspensión.
  • Fiber::suspend($value): pausa la fiber actual y entrega $value a quien la reanuda.
  • $fiber->resume($value): continúa la ejecución; $value se convierte en el valor devuelto por suspend().
  • $fiber->getReturn(): devuelve el valor retornado por el callback una vez que la fiber termina.

Los valores fluyen en ambas direcciones a través del límite de suspensión.

Paso bidireccional de valores

Una fiber puede emitir una solicitud y recibir una respuesta; este es el fundamento de cómo un bucle de eventos entrega resultados de E/S a las tareas suspendidas.

<?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 introspección de una Fiber

Puede consultar el ciclo de vida de una fiber. Llamar a resume() sobre una fiber terminada lanza FiberError, por lo que debe protegerse con estas comprobaciones al crear un scheduler.

<?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

Construcción de un scheduler pequeño

Fibers más una cola equivalen a un scheduler cooperativo. Cada tarea se suspende para ceder el control; el scheduler las ejecuta por turnos hasta que todas terminan. Este es el esqueleto interno de cualquier runtime así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();
    }
}

Excepciones entre límites

throwInto() (llamado throw() en la API como $fiber->throw()) inyecta una excepción en el punto de suspensión; así es como un bucle comunica un fallo de E/S a la tarea que está esperando. La excepción aparece exactamente donde la fiber se pausó.

<?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

Fibers frente a Generators

Los Generators (yield) también se suspenden, pero únicamente la función de nivel superior. Para esperar desde una función auxiliar anidada con generators, debe usar yield from hasta el final de la pila, haciendo que todas las funciones queden condicionadas. Las Fibers suspenden la pila completa desde cualquier nivel de profundidad, por lo que una llamada profundamente anidada puede ejecutar Fiber::suspend() sin que sus llamadores lo sepan. Por eso await puede ser una llamada de función normal en lugar de un 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');

La restricción de suspensión

Hay una regla estricta: solo puede ejecutar Fiber::suspend() desde dentro de una fiber. Suspender desde el hilo principal o a través de un callback de nivel C que no admita fibers (algunos comparadores antiguos de usort y ciertos callbacks internos) lanza FiberError: Cannot suspend outside of a fiber. Las bibliotecas ocultan este detalle asegurándose de que todo el código del usuario se ejecute dentro de una fiber controlada por el bucle.

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

Cómo utilizan las bibliotecas las Fibers

Rara vez se escriben Fibers sin abstraerlas en el código de una aplicación. Frameworks como Amp v3 y ReactPHP (mediante fibers) las encapsulan: await($promise) llama internamente a Fiber::suspend(), registra una continuación en el bucle de eventos y ejecuta resume() en su fiber cuando termina la operación de E/S. Su código parece síncrono; el runtime se encarga de aparcar y planificar la ejecución.

<?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
}

Consideraciones sobre memoria y ciclo de vida

Cada fiber reserva su propia pila, por lo que crear cientos de miles tiene un coste de memoria (aunque es mucho más ligero que usar hilos del sistema operativo). Una fiber suspendida indefinidamente nunca se recolecta si algo sigue manteniendo una referencia a ella, lo que constituye una fuga sutil en servidores de larga duración. Además, si el callback de una fiber lanza una excepción no capturada, esta se propaga fuera de la llamada a resume()/start(), por lo que el scheduler debe envolver las reanudaciones en un bloque try/catch.

<?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;
}

Comprobación rápida

¿Qué ventaja clave tienen las Fibers frente a los generators para la asincronía?

Resumen

Las Fibers son la primitiva de concurrencia de bajo nivel de PHP:

  • start(), Fiber::suspend(), resume() y getReturn() pausan y continúan una pila de llamadas completa, pasando valores en ambas direcciones.
  • Los métodos de estado (isSuspended, isTerminated) y throw() permiten crear un scheduler cooperativo e inyectar errores de E/S.
  • A diferencia de los generators, una fiber se suspende desde cualquier nivel de profundidad, lo que permite un await() transparente.
  • Solo puede suspenderse desde dentro de una fiber; frameworks como Amp y ReactPHP encapsulan las fibers para que el código asíncrono se lea como código síncrono.

Preguntas frecuentes

¿La lección «Fibers de PHP 8.1» es gratis?

Sí — el texto completo de «Fibers de PHP 8.1» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de PHP Academy, actualiza a CoddyKit PRO. El curso de PHP Academy incluye 4 lecciones en total.

¿Qué aprenderé en «Fibers de PHP 8.1»?

Pause y reanude la ejecución mediante Fibers nativas. Practicas PHP Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar PHP Academy?

No se requiere experiencia previa. PHP Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 2 de 4.

¿Cuánto tiempo toma la lección «Fibers de PHP 8.1»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de PHP Academy?

Sí. Cada lección de PHP Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. El modelo de concurrencia de PHP
  2. Fibers de PHP 8.1
  3. Bucles de eventos con ReactPHP
  4. Servidores de alto rendimiento con Swoole
← Volver a PHP Academy