PHPackages                             initphp/fiber-loops - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Queues &amp; Workers](/categories/queues)
4. /
5. initphp/fiber-loops

ActiveLibrary[Queues &amp; Workers](/categories/queues)

initphp/fiber-loops
===================

A minimal cooperative task scheduler (event loop) for PHP, built on native fibers.

2.0.0(3w ago)611MITPHPPHP &gt;=8.1CI passing

Since Jul 13Pushed 3w ago1 watchersCompare

[ Source](https://github.com/InitPHP/FiberLoops)[ Packagist](https://packagist.org/packages/initphp/fiber-loops)[ Docs](https://github.com/InitPHP/FiberLoops)[ RSS](/packages/initphp-fiber-loops/feed)WikiDiscussions main Synced today

READMEChangelog (2)Dependencies (3)Versions (4)Used By (0)

InitPHP FiberLoops
==================

[](#initphp-fiberloops)

[![CI](https://github.com/InitPHP/FiberLoops/actions/workflows/ci.yml/badge.svg)](https://github.com/InitPHP/FiberLoops/actions/workflows/ci.yml)[![License: MIT](https://camo.githubusercontent.com/8bb50fd2278f18fc326bf71f6e88ca8f884f72f179d3e555e20ed30157190d0d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d677265656e2e737667)](LICENSE)[![PHP Version](https://camo.githubusercontent.com/90f0558365d407417bbfff282d2a7f663b5b03a7eaf103626d33e32f8c9a0a3f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d254532253839254135253230382e312d3737376262342e737667)](composer.json)

> A **minimal cooperative task scheduler** for PHP, built on native [fibers](https://www.php.net/manual/en/language.fibers.php). Run several tasks on a single thread, hand control back and forth at points *you* choose, and wait for sub-tasks to finish — in a few dozen lines of dependency-free code.

[![php-fiber](https://user-images.githubusercontent.com/104234499/178588669-e6a6384b-5712-45ec-9676-fe8900fd625f.png)](https://user-images.githubusercontent.com/104234499/178588669-e6a6384b-5712-45ec-9676-fe8900fd625f.png)

What it is (and is not)
-----------------------

[](#what-it-is-and-is-not)

FiberLoops is a tiny scheduler. You queue tasks with `defer()` and drive them with `run()`. Each task is a fiber; the loop advances the tasks **round-robin**, running each one until it **cooperatively yields** (`next()` / `sleep()`) or returns.

Scheduling is **cooperative, not preemptive**: nothing interrupts a task. A task keeps the CPU until it yields or finishes, so long-running tasks must call `next()` periodically to let their siblings make progress. There is no I/O reactor, no stream/timer polling, no threads — it is a scheduling primitive you can build those things on top of, not a full async runtime like ReactPHP or Amp.

Requirements
------------

[](#requirements)

- PHP **8.1+** (fibers are a core language feature since 8.1 — no extension needed)

Installation
------------

[](#installation)

```
composer require initphp/fiber-loops
```

Quick start
-----------

[](#quick-start)

```
require_once 'vendor/autoload.php';

use InitPHP\FiberLoops\Loop;

$loop = new Loop();

$loop->defer(function () use ($loop) {
    foreach (['a', 'b', 'c'] as $step) {
        echo "task-1: $step\n";
        $loop->next();              // yield: let other tasks run
    }
});

$loop->defer(function () use ($loop) {
    foreach (['x', 'y', 'z'] as $step) {
        echo "task-2: $step\n";
        $loop->next();
    }
});

$loop->run();                       // drive every task to completion
```

```
task-1: a
task-2: x
task-1: b
task-2: y
task-1: c
task-2: z

```

The two tasks interleave because each one yields with `next()` after every step. Remove the `next()` calls and the first task would run to completion before the second one started.

The API
-------

[](#the-api)

`Loop` implements `InitPHP\FiberLoops\LoopInterface`. Depend on the interface when you want to substitute or mock the scheduler.

MethodDescription`defer(callable|Fiber $task): void`Queue a task. A callable is wrapped in a fiber. Safe to call during `run()`.`run(): void`Run every queued task to completion (blocks until the queue is empty).`next(mixed $value = null): mixed`Yield from the current task back to the scheduler. **Must run inside a fiber.**`sleep(int|float $seconds): void`Cooperatively pause the current task. **Must run inside a fiber.**`await(callable|Fiber $task): mixed`Run a task to completion and return its value, yielding while it works.### `defer()` and `run()`

[](#defer-and-run)

`defer()` queues work; `run()` executes it. A task added *during* `run()` (from inside another task) is picked up on the next scheduling pass, so tasks can spawn more tasks.

### `next()`

[](#next)

`next()` is the yield point. Calling it suspends the current task and lets the scheduler advance the others; the task resumes where it left off on the next pass. It must be called from within a fiber (i.e. inside a deferred or awaited task) — calling it from the main script throws a `LoopException`:

```
$loop->next(); // LoopException: Loop::next() must be called from within a fiber...
```

> The bundled scheduler resumes tasks without a value, so `next()` returns `null`under `run()` and `await()`. The `$value` argument is reserved for custom drivers and is ignored here.

### `sleep()`

[](#sleep)

`sleep()` pauses the current task for at least the given number of seconds while letting sibling tasks keep running:

```
$loop = new Loop();

$loop->defer(function () use ($loop) {
    $loop->sleep(0.2);              // yields repeatedly for ~200ms
    foreach (range(0, 5) as $value) {
        echo $value . PHP_EOL;
    }
});

$loop->defer(function () use ($loop) {
    foreach (range(6, 9) as $value) {
        echo $value . PHP_EOL;
    }
});

$loop->run();
```

```
6
7
8
9
0
1
2
3
4
5

```

The second task finishes first because the first one is sleeping. `sleep()` is a **busy-wait** that yields on every iteration: siblings progress, but the loop does not idle the CPU. `sleep(0)` (or any non-positive value) returns immediately without yielding. See [docs/caveats.md](docs/caveats.md) for the implications.

### `await()`

[](#await)

`await()` runs a task to completion and returns its value. From the main script it drives the task synchronously:

```
$loop = new Loop();

$user = $loop->await(function () use ($loop) {
    $loop->next();                  // may yield while doing work
    return ['id' => 42, 'name' => 'Ada'];
});

echo "user: {$user['id']} / {$user['name']}\n";   // user: 42 / Ada
```

Called **from inside a task**, `await()` yields to the scheduler while the awaited sub-task works, so other tasks keep running in the meantime:

```
$loop = new Loop();

$loop->defer(function () use ($loop) {
    echo "worker: awaiting a sub-task\n";
    $sum = $loop->await(function () use ($loop) {
        $total = 0;
        foreach (range(1, 3) as $n) {
            $total += $n;
            $loop->next();
        }
        return $total;
    });
    echo "worker: sub-task returned $sum\n";
});

$loop->defer(function () use ($loop) {
    foreach (['tick', 'tick', 'tick'] as $t) {
        echo "heartbeat: $t\n";
        $loop->next();
    }
});

$loop->run();
```

```
worker: awaiting a sub-task
heartbeat: tick
heartbeat: tick
heartbeat: tick
worker: sub-task returned 6

```

`await()` accepts a callable or a `Fiber`, started or not.

Error handling
--------------

[](#error-handling)

`next()` and `sleep()` must be called from within a fiber. Doing otherwise throws `InitPHP\FiberLoops\Exception\LoopException` (a `RuntimeException`) with an actionable message, instead of PHP's bare `FiberError`.

Documentation
-------------

[](#documentation)

Full guides live in [`docs/`](docs/):

GuideWhat it covers[Getting started](docs/getting-started.md)Install, your first two tasks, how the loop runs them.[Concepts](docs/concepts.md)The scheduling model: fibers, the round-robin queue, cooperative yielding.[API reference](docs/api/README.md)Every method, its signature, behaviour and edge cases.[await &amp; concurrency](docs/await-and-concurrency.md)Awaiting sub-tasks from the main context and from inside a task.[Caveats &amp; gotchas](docs/caveats.md)Busy-wait `sleep()`, in-fiber preconditions, non-preemptive scheduling.Testing
-------

[](#testing)

```
composer install
composer test        # PHPUnit
composer ci          # cs-check + phpstan + tests
```

Contributing
------------

[](#contributing)

Contributions are welcome. Please read the org-wide [Contributing guide](https://github.com/InitPHP/.github/blob/main/CONTRIBUTING.md)and the [Security policy](https://github.com/InitPHP/.github/blob/main/SECURITY.md). Fork, branch, add tests for your change, and open a pull request.

Credits
-------

[](#credits)

- [Muhammet ŞAFAK](https://www.muhammetsafak.com.tr) &lt;&gt;

License
-------

[](#license)

Copyright © 2022 InitPHP — released under the [MIT License](LICENSE).

###  Health Score

46

—

FairBetter than 92% of packages

Maintenance95

Actively maintained with recent releases

Popularity10

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity59

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~714 days

Total

3

Last Release

23d ago

Major Versions

1.x-dev → 2.0.02026-06-10

### Community

Maintainers

![](https://www.gravatar.com/avatar/4b6b34f3ac8938d8ee52ba3bd260680855dc5715c7b2929d9380de30d15a67dd?d=identicon)[muhammetsafak](/maintainers/muhammetsafak)

---

Top Contributors

[![muhammetsafak](https://avatars.githubusercontent.com/u/104234499?v=4)](https://github.com/muhammetsafak "muhammetsafak (6 commits)")

---

Tags

asyncconcurrencycooperative-schedulingcoroutineevent-loopfiberfibersinitphpphpschedulerevent-loopasyncschedulerconcurrencycoroutineloopFibersfiberinitphpcooperative

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/initphp-fiber-loops/health.svg)

```
[![Health](https://phpackages.com/badges/initphp-fiber-loops/health.svg)](https://phpackages.com/packages/initphp-fiber-loops)
```

###  Alternatives

[amphp/amp

A non-blocking concurrency framework for PHP applications.

4.4k133.8M433](/packages/amphp-amp)[revolt/event-loop

Rock-solid event loop for concurrent PHP applications.

92553.8M226](/packages/revolt-event-loop)[react/promise-timer

A trivial implementation of timeouts for Promises, built on top of ReactPHP.

34148.1M113](/packages/react-promise-timer)[sabre/event

sabre/event is a library for lightweight event-based programming

35229.1M29](/packages/sabre-event)[symplely/coroutine

Cooperative multitasking using generators. The basics of coroutines, async and await!

621.6k2](/packages/symplely-coroutine)[clue/mq-react

Mini Queue, the lightweight in-memory message queue to concurrently do many (but not too many) things at once, built on top of ReactPHP

145810.0k4](/packages/clue-mq-react)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
