Use PHP 8.1’s Native Poll API Today—No Need to Wait for PHP 8.6

PHP 8.6 adds a native Io\Poll API that brings epoll/kqueue support into the engine, and a Symfony polyfill makes the same API usable on PHP 8.1‑8.5, enabling Workerman’s event loop to run without C extensions; benchmarks show up to double the throughput with zero code changes when upgrading.

Open Source Tech Hub
Open Source Tech Hub
Open Source Tech Hub
Use PHP 8.1’s Native Poll API Today—No Need to Wait for PHP 8.6

What the new Poll API provides

PHP 8.6 merged the Poll API RFC, adding Io\Poll which gives native support for epoll (Linux), kqueue (macOS/BSD) and WSAPoll (Windows). It removes the 1024‑fd limit of stream_select(), provides O(1) readiness checks, and requires no C extensions.

Zero extension dependency – built into the engine, usable directly from Composer packages.

Standard multiplexing – ready‑event notification with O(1) fd retrieval.

No fd limit – eliminates the FD_SETSIZE 1024 restriction.

Fiber integration – forms a native foundation for future async frameworks.

API concepts

Io\Poll\Context

– polling context that registers and watches multiple handles, supporting Read, Write, Error, Hang‑up events. Io\Poll\Event – enum of event types, e.g. Event::Read.

Watcher – object returned by wait(), can carry custom data and be modified or removed dynamically. StreamPollHandle – wraps a native PHP stream resource into a handle recognizable by the poll API.

Official‑style TCP server example

use Io\Poll\Context;
use Io\Poll\Event;
use StreamPollHandle;

$server = stream_socket_server('tcp://127.0.0.1:8080');
$poll = new Context();
$poll->add(new StreamPollHandle($server), [Event::Read]);

foreach ($poll->wait(timeoutSeconds: 30) as $watcher) {
    if ($watcher->hasTriggered(Event::Read)) {
        $connection = stream_socket_accept($watcher->getHandle()->getStream());
        // handle new connection...
    }
}

Difference from stream_select()

stream_select()

requires rebuilding the fd set each round (O(n) complexity) and is limited to 1024 descriptors. The Poll API registers fds once; each wait() call returns only the ready descriptors, eliminating repeated array management.

Symfony polyfill for PHP 8.1‑8.5

The Symfony team released symfony/polyfill-io-poll 1.41.0, back‑porting the API to older PHP versions. The polyfill implements the same interface using stream_select() internally, supports only level‑triggered events, and its wait() signature uses integer seconds instead of Time\Duration. The polyfill automatically yields to the native implementation when running on PHP 8.6+.

Workerman integration

Workerman 5.x abstracts I/O multiplexing behind Workerman\Events\EventInterface. Built‑in drivers include Select, Ev, Event, Swoole, Swow, etc. Switching drivers is a single line:

Worker::$eventLoopClass = \Workerman\Events\Select::class;

The Poll driver implements the full interface (onReadable/offReadable, onWritable/offWritable, delay/offDelay, repeat/offRepeat, onSignal/offSignal, run/stop). Installation:

composer require tinywan/workerman-event-poll

Usage example

<?php
require __DIR__ . '/vendor/autoload.php';

use Workerman\Worker;
use Workerman\Events\Poll;

Worker::$eventLoopClass = Poll::class;

$worker = new Worker('http://0.0.0.0:8080');
$worker->onMessage = function ($connection, $request) {
    $connection->send('hello');
};

Worker::runAll();

Performance benchmarks

Single‑process wrk test ( -t2 -c200 -d20s) with minimal HTTP response:

PHP 8.6 + native Poll (epoll) – ~51,500 RPS (best overall).

Swoole native (no coroutine) – ~42,000 RPS (C extension engine).

PHP 8.4 + Poll (polyfill) – ~25,750 RPS (≈15 % faster than built‑in Select).

PHP 8.4 + Select (built‑in) – ~22,450 RPS (Workerman default fallback).

In an 8‑process scenario, native Poll on PHP 8.6 reaches ~119k RPS, while the polyfill peaks at ~71k RPS, still behind Select (~99k RPS). The polyfill’s value lies in API compatibility and a zero‑change upgrade path; for maximum multi‑process throughput on PHP 8.1‑8.5, Select/Ev/Event remain preferable.

Conclusion

On PHP 8.1‑8.5 single‑process workloads the Poll driver runs about 15 % faster than the default Select and removes the fd‑limit concern. Once PHP 8.6 is adopted, the same code automatically switches to a native epoll implementation, effectively doubling throughput without code modifications.

References

PHP RFC: Poll API – wiki.php.net/rfc/poll_api Symfony Polyfill 1.41.0 release announcement –

symfony.com/blog/symfony-polyfill-1-41-0-released-io-poll-now-available

Symfony polyfill repository – github.com/symfony/polyfill Workerman Poll driver repository – github.com/Tinywan/workerman-event-Poll Benchmark script – BENCHMARK.md and

examples/bench.sh
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

performance benchmarkPHPepollworkermanpoll apisymfony polyfill
Open Source Tech Hub
Written by

Open Source Tech Hub

Sharing cutting-edge internet technologies and practical AI resources.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.