PHP / Magento Dev Blog

  • Publikacje
  • O autorze
  • Kontakt

PHP Fibers – cooperative multitasking, async bez rozszerzeń, ReactPHP

by Henryk Tews / wtorek, 30 czerwca 2026 / Opublikowano w PHP

Fibers weszły do PHP w wersji 8.1 jako mechanizm cooperative multitasking – możliwość zawieszenia i wznowienia wykonania funkcji w dowolnym miejscu. To nie są wątki ani procesy – Fiber działa w tym samym wątku PHP, ale pozwala przełączać się między zadaniami bez blokowania. Pokażę jak działają Fibers, gdzie mają sens i jak biblioteki async (ReactPHP, Amp) używają ich pod spodem.

Czym jest Fiber

Fiber to funkcja która może być zawieszona (Fiber::suspend()) i wznowiona ($fiber->resume()). Różnica od zwykłej funkcji: nie musi dobiec do końca zanim sterowanie wróci do wywołującego. Różnica od generatora: Fiber może przyjmować wartości przy wznowieniu i zwracać wartości przy zawieszeniu w obie strony.

<?php

declare(strict_types=1);

// Podstawowy Fiber
$fiber = new Fiber(function(): string {
    echo "Fiber: start\n";

    $value = Fiber::suspend('pierwsza pauza');  // zawieś, zwróć wartość do wywołującego
    echo "Fiber: wznowiony z wartością: {$value}\n";

    $value2 = Fiber::suspend('druga pauza');
    echo "Fiber: wznowiony ponownie: {$value2}\n";

    return 'fiber zakończony';
});

$result1 = $fiber->start();         // uruchom do pierwszego suspend()
echo "Główny kod otrzymał: {$result1}\n";  // "pierwsza pauza"

$result2 = $fiber->resume('dane 1'); // wznów, przekaż wartość
echo "Główny kod otrzymał: {$result2}\n";  // "druga pauza"

$fiber->resume('dane 2');            // wznów do końca
echo "Fiber zakończony: " . $fiber->getReturn() . "\n";

// Output:
// Fiber: start
// Główny kod otrzymał: pierwsza pauza
// Fiber: wznowiony z wartością: dane 1
// Główny kod otrzymał: druga pauza
// Fiber: wznowiony ponownie: dane 2
// Fiber zakończony: fiber zakończony

Scheduler – przełączanie między Fiberami

<?php

declare(strict_types=1);

// Prosty scheduler który przełącza się między Fiberami
class FiberScheduler
{
    /** @var Fiber[] */
    private array $fibers = [];
    private array $queue  = [];

    public function add(Fiber $fiber): void
    {
        $this->fibers[] = $fiber;
        $this->queue[]  = $fiber;
    }

    public function run(): void
    {
        // Uruchom wszystkie Fibery
        foreach ($this->fibers as $fiber) {
            $fiber->start();
        }

        // Przetwarzaj kolejkę dopóki są zawieszone Fibery
        while (!empty($this->queue)) {
            $fiber = array_shift($this->queue);

            if ($fiber->isSuspended()) {
                $fiber->resume();
                if ($fiber->isSuspended()) {
                    $this->queue[] = $fiber; // z powrotem do kolejki
                }
            }
        }
    }
}

// Symulacja "asynchronicznych" zadań
function fetchData(string $url, int $delay): string
{
    echo "Pobieranie {$url}...\n";
    Fiber::suspend(); // oddaj sterowanie

    // Symulacja czekania (w prawdziwym kodzie: nieblokujący I/O)
    for ($i = 0; $i < $delay; $i++) {
        Fiber::suspend();
    }

    return "dane z {$url}";
}

$scheduler = new FiberScheduler();

$scheduler->add(new Fiber(function() {
    $result = fetchData('https://api.example.com/orders', 2);
    echo "Gotowe: {$result}\n";
}));

$scheduler->add(new Fiber(function() {
    $result = fetchData('https://api.example.com/products', 1);
    echo "Gotowe: {$result}\n";
}));

$scheduler->run();
// products kończy się przed orders (mniejszy delay)
// bez Fiberów byłyby sekwencyjne

Fibers w ReactPHP

<?php

// ReactPHP od wersji 3.0 używa Fiberów pod spodem
// pozwala pisać kod synchronicznie który działa asynchronicznie

require 'vendor/autoload.php';

use React\Http\Browser;
use React\EventLoop\Loop;

// Stary styl (Promise-based)
$browser = new Browser();
$browser->get('https://httpbin.org/get')
    ->then(function(\Psr\Http\Message\ResponseInterface $response) {
        echo $response->getBody();
    });

// Nowy styl (Fiber-based, ReactPHP 3+)
// Wygląda synchronicznie, działa asynchronicznie
React\Async\async(function() {
    $browser   = new Browser();
    $response1 = React\Async\await($browser->get('https://httpbin.org/get'));
    $response2 = React\Async\await($browser->get('https://httpbin.org/post'));

    // Oba requesty wykonują się sekwencyjnie w kodzie
    // ale event loop może je przeplatać
    echo strlen((string)$response1->getBody()) . "\n";
    echo strlen((string)$response2->getBody()) . "\n";
})();

Fibers vs Generatory vs Promises

Mechanizm Zawieszenie Komunikacja Zastosowanie
Generator yield Jednostronna (yield value) Iteracja, lazy sequences
Fiber Fiber::suspend() Dwustronna (suspend/resume) Cooperative multitasking
Promise then/catch Callback-based Async API calls
async/await await (nad Fiberem) Synchroniczny styl Czytelny async kod

Praktyczne zastosowanie – batch processor

<?php

declare(strict_types=1);

// Przetwarzanie dużej kolekcji bez blokowania innych operacji
class BatchProcessor
{
    private array $pendingFibers = [];

    public function process(array $items, callable $handler, int $concurrency = 5): array
    {
        $results = [];
        $chunks  = array_chunk($items, $concurrency);

        foreach ($chunks as $chunk) {
            $fibers = [];

            foreach ($chunk as $key => $item) {
                $fiber = new Fiber(function() use ($item, $handler, $key, &$results) {
                    $results[$key] = $handler($item);
                });
                $fibers[] = $fiber;
                $fiber->start();
            }

            // Dokończ wszystkie Fibery w tym chunku
            $running = true;
            while ($running) {
                $running = false;
                foreach ($fibers as $fiber) {
                    if ($fiber->isSuspended()) {
                        $fiber->resume();
                        $running = true;
                    }
                }
            }
        }

        return $results;
    }
}

// Użycie
$processor = new BatchProcessor();
$items     = range(1, 100);

$results = $processor->process($items, function(int $item): int {
    Fiber::suspend(); // symulacja I/O
    return $item * 2;
}, concurrency: 10);

echo count($results) . " wyników przetworzonych\n";

Podsumowanie

Fibers to niskopoziomowy mechanizm cooperative multitasking w PHP. Nie zastępują wątków ani procesów – działają w jednym wątku. Ich prawdziwa siła ujawnia się przez biblioteki wyższego poziomu: ReactPHP, Amp, Revolt. Bezpośrednie użycie Fiberów jest rzadkie – częściej piszesz kod używając async/await z tych bibliotek, które pod spodem zarządzają Fiberami. W kontekście Magento 2 Fibers mogą być użyteczne w skryptach CLI do równoległego przetwarzania dużych kolekcji danych.

About Henryk Tews

Co możesz przeczytać następne

PHP 8.4 premiera – property hooks w prod, asymmetric visibility, BcMath\Number, array_find
PHP 8.1 preview – enumy, readonly properties, intersection types, fibers
Trendy 2025 – FrankenPHP, AI tooling update, OpenSearch, Hyvä konsolidacja
  • Publikacje
  • O autorze
  • Kontakt

© 2026 Created by

GÓRA
Zarządzaj zgodą
Aby zapewnić jak najlepsze wrażenia, korzystamy z technologii, takich jak pliki cookie, do przechowywania i/lub uzyskiwania dostępu do informacji o urządzeniu. Zgoda na te technologie pozwoli nam przetwarzać dane, takie jak zachowanie podczas przeglądania lub unikalne identyfikatory na tej stronie. Brak wyrażenia zgody lub wycofanie zgody może niekorzystnie wpłynąć na niektóre cechy i funkcje.
Funkcjonalne Zawsze aktywne
Przechowywanie lub dostęp do danych technicznych jest ściśle konieczny do uzasadnionego celu umożliwienia korzystania z konkretnej usługi wyraźnie żądanej przez subskrybenta lub użytkownika, lub wyłącznie w celu przeprowadzenia transmisji komunikatu przez sieć łączności elektronicznej.
Preferencje
Przechowywanie lub dostęp techniczny jest niezbędny do uzasadnionego celu przechowywania preferencji, o które nie prosi subskrybent lub użytkownik.
Statystyka
Przechowywanie techniczne lub dostęp, który jest używany wyłącznie do celów statystycznych. Przechowywanie techniczne lub dostęp, który jest używany wyłącznie do anonimowych celów statystycznych. Bez wezwania do sądu, dobrowolnego podporządkowania się dostawcy usług internetowych lub dodatkowych zapisów od strony trzeciej, informacje przechowywane lub pobierane wyłącznie w tym celu zwykle nie mogą być wykorzystywane do identyfikacji użytkownika.
Marketing
Przechowywanie lub dostęp techniczny jest wymagany do tworzenia profili użytkowników w celu wysyłania reklam lub śledzenia użytkownika na stronie internetowej lub na kilku stronach internetowych w podobnych celach marketingowych.
  • Zarządzaj opcjami
  • Zarządzaj serwisami
  • Zarządzaj {vendor_count} dostawcami
  • Przeczytaj więcej o tych celach
Zobacz preferencje
  • {title}
  • {title}
  • {title}