Fibers w PHP 8.1
Proszę wstrzymywać i wznawiać wykonywanie za pomocą natywnych Fibers.
Fibers w PHP 8.1 to bezpłatna lekcja PHP Academy na CoddyKit. To lekcja 2 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej PHP Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs PHP Academy zawiera 4 lekcji w sumie.
Co dają Fibers
PHP 8.1 dodał Fibers: niskopoziomowy prymityw rdzenia, który pozwala wstrzymać wykonywany stos wywołań i wznowić go później z zupełnie innego miejsca. Fiber to pełny, niezależny stos, który można zawiesić w dowolnym punkcie i kontynuować bez rozwijania stosu. To brakujący element, dzięki któremu biblioteki mogą zastąpić łańcuchy promisów synchronicznie wyglądającym await — mechanizm ten stanowi podstawę współczesnych API ReactPHP i Amp.
Pierwszy Fiber
Należy utworzyć Fiber za pomocą callbacku, uruchomić go przez start() i pozwolić mu samodzielnie wywołać suspend(). W punkcie zawieszenia sterowanie wraca do wywołującego; resume() wznawia wykonanie dokładnie w tym miejscu.
<?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";Cztery podstawowe metody
API jest niewielkie:
$fiber->start(...$args)— rozpoczyna wykonanie; zwraca pierwszą wartość zawieszenia.Fiber::suspend($value)— wstrzymuje bieżący Fiber, przekazując$valuewznawiającemu wykonanie.$fiber->resume($value)— wznawia wykonanie;$valuestaje się wartością zwracaną przezsuspend().$fiber->getReturn()— zwraca wartość callbacku po jego zakończeniu.
Wartości przepływają przez granicę zawieszenia w obu kierunkach.
Dwukierunkowe przekazywanie wartości
Fiber może przekazać żądanie na zewnątrz i odebrać odpowiedź z powrotem — to podstawa sposobu, w jaki pętla zdarzeń dostarcza wyniki operacji wejścia-wyjścia zawieszonym zadaniom.
<?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; // 42Stan i introspekcja Fiberów
Można sprawdzać cykl życia Fiberu. Wywołanie resume() na zakończonym Fiberze zgłasza FiberError, dlatego podczas budowania planisty należy zabezpieczyć się za pomocą tych sprawdzeń.
<?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()); // trueBudowa małego planisty
Fibers i kolejka dają kooperatywny planista. Każde zadanie zawiesza się, aby oddać sterowanie; planista wykonuje zadania cyklicznie, metodą round-robin, aż wszystkie zostaną ukończone. To szkielet każdej asynchronicznej platformy wykonawczej.
<?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();
}
}Wyjątki na granicach
throwInto() (w API nazywane throw(), czyli $fiber->throw()) wstrzykuje wyjątek w punkcie zawieszenia — w ten sposób pętla zgłasza nieudaną operację wejścia-wyjścia oczekującemu zadaniu. Wyjątek pojawia się dokładnie tam, gdzie Fiber został wstrzymany.
<?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 failedFibers a generatory
Generatory (yield) również zawieszają wykonanie — ale tylko zewnętrzną funkcję. Aby oczekiwać w zagnieżdżonym pomocniku za pomocą generatorów, trzeba stosować yield from aż do samego szczytu stosu, oznaczając każdą funkcję jako generator. Fibers zawieszają cały stos z dowolnej głębokości, więc głęboko zagnieżdżone wywołanie może użyć Fiber::suspend(), a jego wywołujący nie muszą o tym wiedzieć. Dzięki temu await może być zwykłym wywołaniem funkcji, a nie 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');Ograniczenie zawieszania
Obowiązuje jedna niepodważalna zasada: Fiber::suspend() można wywołać wyłącznie wewnątrz Fiberu. Zawieszenie z głównego wątku lub w ramach wywołania zwrotnego na poziomie C, które nie obsługuje Fibers (na przykład w niektórych starszych komparatorach usort i określonych callbackach wewnętrznych), powoduje wyjątek FiberError: Cannot suspend outside of a fiber. Biblioteki ukrywają ten szczegół, zapewniając, że cały kod użytkownika działa wewnątrz Fiberu sterowanego przez pętlę.
<?php
try {
Fiber::suspend(); // main thread — illegal
} catch (FiberError $e) {
echo $e->getMessage(), PHP_EOL; // Cannot suspend outside of a fiber
}Jak biblioteki używają Fibers
W kodzie aplikacji rzadko pisze się surowe Fibers. Frameworki takie jak Amp v3 i ReactPHP (za pośrednictwem Fibers) opakowują je: await($promise) wewnętrznie wywołuje Fiber::suspend(), rejestruje kontynuację w pętli zdarzeń i wywołuje resume() Fiberu po ukończeniu operacji wejścia-wyjścia. Kod wygląda synchronicznie, a środowisko wykonawcze zajmuje się zawieszaniem i planowaniem.
<?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
}Uwagi dotyczące pamięci i cyklu życia
Każdy Fiber przydziela własny stos, więc uruchomienie setek tysięcy Fiberów ma koszt pamięciowy, choć jest on znacznie mniejszy niż w przypadku wątków systemu operacyjnego. Fiber zawieszony na zawsze nie zostanie usunięty przez mechanizm zbierania śmieci, jeśli coś nadal przechowuje do niego odwołanie — to subtelny wyciek w długo działających serwerach. Ponadto callback Fiberu, który zgłasza nieprzechwycony wyjątek, propaguje go poza wywołanie resume()/start(), dlatego planista musi opakowywać wznowienia w 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;
}Szybki test
Jaka jest kluczowa przewaga Fibers nad generatorami w zastosowaniach asynchronicznych?
Podsumowanie
Fibers to niskopoziomowy prymityw współbieżności w PHP:
start(),Fiber::suspend(),resume()igetReturn()wstrzymują i wznawiają cały stos wywołań, przekazując wartości w obu kierunkach.- Metody stanu (
isSuspended,isTerminated) orazthrow()pozwalają budować kooperatywny planista i wstrzykiwać błędy operacji wejścia-wyjścia. - W przeciwieństwie do generatorów Fiber można zawiesić z dowolnej głębokości, co umożliwia przejrzyste
await(). - Zawieszanie jest dozwolone wyłącznie wewnątrz Fiberu; frameworki takie jak Amp i ReactPHP opakowują Fibers, dzięki czemu kod asynchroniczny wygląda synchronicznie.
Często zadawane pytania
Czy lekcja „Fibers w PHP 8.1” jest bezpłatna?
Tak — pełny tekst „Fibers w PHP 8.1” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu PHP Academy, przejdź na CoddyKit PRO. Kurs PHP Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Fibers w PHP 8.1”?
Proszę wstrzymywać i wznawiać wykonywanie za pomocą natywnych Fibers. Ćwiczysz PHP Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć PHP Academy?
Nie wymagamy żadnego doświadczenia. PHP Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 4.
Ile czasu zajmuje lekcja „Fibers w PHP 8.1”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji PHP Academy?
Tak. Każda lekcja PHP Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.