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 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
Requires PHP 8.3+.
⚡️ Get started by requiring the package using Composer:
composer require nunomaduro/pokio:@dev
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 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
Pokio was created by Nuno Maduro under the MIT license.