memran/marwa-eventloop

PHP Async Event Loop with coroutines, promises, and async I/O

Maintainers

Package info

github.com/memran/marwa-eventloop

pkg:composer/memran/marwa-eventloop

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.0 2026-04-12 19:08 UTC

This package is auto-updated.

Last update: 2026-04-12 19:14:21 UTC


README

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.

PHP Version License PHPUnit PHPStan Packagist Packagist Downloads

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

Requirements

Requirements

  • PHP 8.2+

Installation

composer require memran/marwa-eventloop

Usage

<?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();

Features

Tasks (Promises)

$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();

Coroutines

$loop->async(function () use ($loop) {
    // Use yield to await Tasks
    $result = yield someAsyncOperation();
    return $result;
});

Timers

// 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";
});

Streams

// 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);

Signals

$loop->addSignal(SIGINT, function () use ($loop) {
    echo "Shutting down...\n";
    $loop->stop();
});

Async Utilities

// 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);

Why This Library?

Why Is It Important?

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);
});

Use Cases

  • 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

What Can Be Done?

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

Comparison

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

Real-World Example

// 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)

API

AsyncEventLoop

  • async(callable $coroutine): Task - Run a coroutine
  • defer(callable $callback) - Schedule callback for next tick
  • addTimer(float $interval, callable $callback, bool $periodic = false): int - Add timer
  • addTimeout(float $interval, callable $callback): int - Add timeout
  • cancelTimer(int $timerId): bool - Cancel a timer
  • addReadStream($stream, callable $callback) - Add read stream
  • addWriteStream($stream, callable $callback) - Add write stream
  • removeStream($stream) - Remove stream
  • addSignal(int $signal, callable $callback) - Add signal handler
  • run() - Start the event loop
  • stop() - Stop the event loop
  • getMetrics(): array - Get performance metrics

Task

  • resolve(mixed $value) - Resolve the task
  • reject(Throwable $exception) - Reject the task
  • then(callable $onFulfilled): self - Add fulfillment handler
  • catch(callable $onRejected): self - Add rejection handler
  • await(): mixed - Get the result (throws if rejected)
  • isFulfilled(): bool - Check if resolved
  • isRejected(): bool - Check if rejected
  • isPending(): bool - Check if still pending

Testing

Run tests with PHPUnit:

composer test

Or run directly:

vendor/bin/phpunit

Static Analysis

Run PHPStan:

composer phpstan

Or run directly:

vendor/bin/phpstan analyse

License

MIT