<?php
namespace fiberEnabled {
/** @return iterable<int> */
function fibonacciSequence(): iterable
{
$a = 0;
$b = 1;
while (true) {
yield $a;
// Imagine if this had to yield a Promise:
// All callers would also have to return a promise and know how to wait for it to resolve
if (\Fiber::getCurrent()) {
\Fiber::suspend();
}
$c = $a;
$a = $b;
$b += $c;
}
}
function fetch5th(): int
{
foreach (fibonacciSequence() as $key => $i) {
if ($key === 19) {
return $i;
}
}
}
function fetchFirstTen(): array
{
$result = [];
foreach (fibonacciSequence() as $key => $i) {
$result[] = $i;
if ($key === 9) {
return $result;
}
}
}
function file_get_contents(string $file): string
{
if (!\Fiber::getCurrent()) {
return \file_get_contents($file);
}
$stream = fopen($file, 'r');
\stream_set_blocking($stream, false);
\stream_set_read_buffer($stream, 0);
$data = '';
while (!\feof($stream)) {
\Fiber::suspend();
$partial = \stream_get_contents($stream, length: 4); // Simulate read latency
var_dump($partial);
$data .= $partial;
}
\fclose($stream);
return $data;
}
// NOTE: A real fiber event loop would be able to pool these and 'await' them alternatingly.
// If it was waiting for a network request they may return in a different order.
// Fibers can repeatedly suspend and let other fibers continue while waiting for an external condition.
function fiberAll(array $fibers): array {
foreach ($fibers as $key => $fiber) {
if (!$fiber->isStarted()) {
$fiber->start();
}
while ($fiber->isSuspended()) {
echo 'Fiber suspended, resuming...', "\n";
$fiber->resume();
}
}
return $fibers;
}
}
namespace {
file_put_contents('/tmp/test123', 'Some test text data');
// Whether used directly, outside of an event loop...
print_r(\fiberEnabled\fetch5th()); echo "\n";
print_r(\fiberEnabled\fetchFirstTen());
print_r(\fiberEnabled\file_get_contents('/tmp/test123')); echo "\n";
// Or used as part of an event loop...
$fibers = \fiberEnabled\fiberAll([
'fetch5th' => new Fiber(\fiberEnabled\fetch5th(...)),
'fetchFirstTen' => new Fiber(\fiberEnabled\fetchFirstTen(...)),
'fileContent' => new Fiber(fn () => \fiberEnabled\file_get_contents('/tmp/test123')),
]);
print_r($fibers['fetch5th']->getReturn()); echo "\n";
print_r($fibers['fetchFirstTen']->getReturn());
print_r($fibers['fileContent']->getReturn()); echo "\n";
}
Here you find the average performance (time & memory) of each version. A grayed out version indicates it didn't complete successfully (based on exit-code).