nunomaduro / pokio
Pokio is a dead simple asynchronous API for PHP that just works
Fund package maintenance!
nunomaduro
Patreon
www.paypal.com/paypalme/enunomaduro
Installs: 2 751
Dependents: 0
Suggesters: 0
Security: 0
Stars: 231
Watchers: 4
Forks: 19
Open Issues: 3
Requires
- php: ^8.3.0
Requires (Dev)
- laravel/pint: ^1.22.1
- peckphp/peck: ^0.1.3
- pestphp/pest: ^4.0.0
- pestphp/pest-plugin-type-coverage: ^4.0.0
- phpstan/phpstan: ^2.1.17
- rector/rector: ^2.0.17
- symfony/var-dumper: ^7.3.0
Conflicts
- symplify/easy-parallel: <11.2.2
This package is auto-updated.
Last update: 2025-06-04 19:12:47 UTC
README
Caution: This package is a work in progress and it manipulates process lifecycles using low-level and potentially unsafe techniques such as FFI for inter-process communication, and preserving state across process spawns. It is intended strictly for internal use (e.g., performance optimizations in Pest). Use at your own risk—no guarantees are provided.

Pokio
Pokio is a dead simple Asynchronous API for PHP that just works! Here is an example:
$promiseA = async(function () { sleep(2); return 'Task 1'; }); $promiseB = async(function () { sleep(2); return 'Task 2'; }); // just takes 2 seconds... [$resA, $resB] = await([$promiseA, $promiseB]); echo $resA; // Task 1 echo $resB; // Task 2
Installation
Requires PHP 8.3+.
⚡️ Get started by requiring the package using Composer:
composer require nunomaduro/pokio:@dev
Usage
async
The async
global function returns a promise that will eventually resolve the value returned by the given closure.
$promise = async(function () { return 1 + 1; }); var_dump(await($promise)); // int(2)
Similar to other promise libraries, Pokio allows you to chain methods to the promise (like then
, catch
, etc.).
The then
method will be called when the promise resolves successfully. It accepts a closure that will receive the resolved value as its first argument.
$promise = async(fn (): int => 1 + 2) ->then(fn ($result): int => $result + 2) ->then(fn ($result): int => $result * 2); $result = await($promise); var_dump($result); // int(10)
Optionally, you may chain a catch
method to the promise, which will be called if the given closure throws an exception.
$promise = async(function () { throw new Exception('Error'); })->catch(function (Throwable $e) { return 'Rescued: ' . $e->getMessage(); }); var_dump(await($promise)); // string(16) "Rescued: Error"
If you don't want to use the catch
method, you can also use native try/catch
block.
$promise = async(function () { throw new Exception('Error'); }); try { await($promise); } catch (Throwable $e) { var_dump('Rescued: ' . $e->getMessage()); // string(16) "Rescued: Error" }
Similar to the catch
method, you may also chain a finally
method to the promise, which will be called regardless of whether the promise resolves successfully or throws an exception.
$promise = async(function (): void { throw new RuntimeException('Exception 1'); })->finally(function () use (&$called): void { echo "Finally called\n"; });
If you return a promise from the closure, it will be awaited automatically.
$promise = async(function () { return async(function () { return 1 + 1; }); }); var_dump(await($promise)); // int(2)
await
The await
global function will block the current process until the given promise resolves.
$promise = async(function () { sleep(2); return 1 + 1; }); var_dump(await($promise)); // int(2)
You may also pass an array of promises to the await
function, which will be awaited simultaneously.
$promiseA = async(function () { sleep(2); return 1 + 1; }); $promiseB = async(function () { sleep(2); return 2 + 2; }); var_dump(await([$promiseA, $promiseB])); // array(2) { [0]=> int(2) [1]=> int(4) }
Follow Nuno
- Follow the creator Nuno Maduro:
- YouTube: youtube.com/@nunomaduro — Videos every weekday
- Twitch: twitch.tv/enunomaduro — Streams (almost) every weekday
- Twitter / X: x.com/enunomaduro
- LinkedIn: linkedin.com/in/nunomaduro
- Instagram: instagram.com/enunomaduro
- Tiktok: tiktok.com/@enunomaduro
License
Pokio was created by Nuno Maduro under the MIT license.