A PHP Fiber based async event loop library for PHP 8.2+. Build high-performance asynchronous PHP applications with coroutines, promises (Task), non-blocking I/O, timers, and signal handling.
Keywords: PHP async, PHP event loop, PHP Fiber, PHP coroutine, PHP promise, async PHP, non-blocking I/O, asynchronous PHP, PHP concurrency, PHP timers, PHP streams
- PHP 8.2+
composer require memran/marwa-eventloop<?php
require_once __DIR__ . '/vendor/autoload.php';
use Marwa\Eventloop\AsyncEventLoop;
use Marwa\Eventloop\AsyncIO;
$loop = new AsyncEventLoop();
// Run async coroutine
$task = $loop->async(function () use ($loop) {
echo "Task started\n";
// Sleep asynchronously
yield AsyncIO::sleep(1, $loop);
echo "Task completed\n";
return "Result";
});
// Handle result
$task->then(function ($result) {
echo "Success: $result\n";
})->catch(function ($e) {
echo "Error: " . $e->getMessage() . "\n";
});
// Stop after 5 seconds
$loop->addTimer(5, function () use ($loop) {
$loop->stop();
});
$loop->run();$task = new Task();
$task->resolve($value);
// or
$task->reject(new \Exception('Error'));
// Chain handlers
$task->then(function ($value) {
return $value * 2;
})->catch(function ($e) {
echo "Error: " . $e->getMessage() . "\n";
});
// Await result (inside coroutine)
$result = $task->await();$loop->async(function () use ($loop) {
// Use yield to await Tasks
$result = yield someAsyncOperation();
return $result;
});// One-time timer (3 seconds)
$loop->addTimer(3.0, function () {
echo "Timer fired\n";
});
// Periodic timer (every 1 second)
$loop->addTimer(1.0, function () {
echo "Every second\n";
}, true);
// Timeout
$loop->addTimeout(5.0, function () {
echo "Operation timed out\n";
});// Read stream
$loop->addReadStream($stream, function ($stream) {
$data = fread($stream, 1024);
// process data
});
// Write stream
$loop->addWriteStream($stream, function ($stream) {
fwrite($stream, "data");
});
// Remove stream
$loop->removeStream($stream);$loop->addSignal(SIGINT, function () use ($loop) {
echo "Shutting down...\n";
$loop->stop();
});// Async sleep
yield AsyncIO::sleep(1.5, $loop);
// Async file read
$content = yield AsyncIO::readFile('file.txt', $loop);
// Timeout wrapper
$task = AsyncIO::timeout($originalTask, 5.0, $loop);PHP has traditionally been synchronous with blocking I/O. This PHP Fiber based event loop brings asynchronous, non-blocking I/O to PHP using PHP 8.2+ native Fibers - a coroutine implementation that enables writing concurrent code without callbacks.
Traditional PHP:
// Blocking - page loads slowly
$data = fetchApiData();
processData($data);With Marwa Event Loop:
// Non-blocking - handles multiple requests concurrently
$loop->async(function() {
$data = yield fetchApiData();
return processData($data);
});- High-performance web servers - Handle thousands of concurrent connections
- Real-time applications - WebSockets, chat systems, live updates
- Microservices - Multiple I/O operations without thread overhead
- API gateways - Aggregate data from multiple sources concurrently
- Background workers - Process tasks asynchronously without blocking
- File I/O operations - Non-blocking file reads/writes
- External API calls - Fetch multiple APIs simultaneously
| Feature | Description |
|---|---|
| Concurrent Tasks | Run multiple async operations in parallel |
| Non-blocking I/O | Handle streams, sockets, files without blocking |
| Timers & Intervals | Schedule delayed and periodic tasks |
| Graceful Shutdown | Handle signals (SIGINT, SIGTERM) properly |
| Timeout Handling | Prevent operations from hanging indefinitely |
| Promise/Task Chain | Compose async operations like JavaScript promises |
| Coroutines | Write async code using synchronous-looking syntax |
| Approach | Performance | Complexity | PHP Version |
|---|---|---|---|
| PHP Fiber Event Loop | High | Low | 8.2+ |
| ReactPHP | High | Medium | 7.1+ |
| Swoole | Very High | High | 7.4+ |
| Traditional (sync) | Low | Low | Any |
// Fetch data from multiple APIs concurrently
$loop = new AsyncEventLoop();
$apis = [
'users' => 'https://api.example.com/users',
'posts' => 'https://api.example.com/posts',
'comments' => 'https://api.example.com/comments',
];
$tasks = [];
foreach ($apis as $name => $url) {
$tasks[$name] = $loop->async(function() use ($url) {
return yield fetchAsync($url); // Non-blocking HTTP request
});
}
// All requests run concurrently
$results = awaitAll($tasks);
// Response time: ~100ms instead of ~300ms (sequential)async(callable $coroutine): Task- Run a coroutinedefer(callable $callback)- Schedule callback for next tickaddTimer(float $interval, callable $callback, bool $periodic = false): int- Add timeraddTimeout(float $interval, callable $callback): int- Add timeoutcancelTimer(int $timerId): bool- Cancel a timeraddReadStream($stream, callable $callback)- Add read streamaddWriteStream($stream, callable $callback)- Add write streamremoveStream($stream)- Remove streamaddSignal(int $signal, callable $callback)- Add signal handlerrun()- Start the event loopstop()- Stop the event loopgetMetrics(): array- Get performance metrics
resolve(mixed $value)- Resolve the taskreject(Throwable $exception)- Reject the taskthen(callable $onFulfilled): self- Add fulfillment handlercatch(callable $onRejected): self- Add rejection handlerawait(): mixed- Get the result (throws if rejected)isFulfilled(): bool- Check if resolvedisRejected(): bool- Check if rejectedisPending(): bool- Check if still pending
Run tests with PHPUnit:
composer testOr run directly:
vendor/bin/phpunitRun PHPStan:
composer phpstanOr run directly:
vendor/bin/phpstan analyseMIT