Skip to content
PHP News
Search
Implemented PHP 8.6

Polling API

Adds an Io\Poll API to PHP core that uses epoll, kqueue and other system backends, a faster, scalable alternative to stream_select().

Should the Polling API be added to PHP core?

Primary vote · 2/3 majority

33 Yes 1 No 4 abstain 97% approval

This poll has closed.

The RFC passed 33 to 1, with 4 abstaining, clearing the two-thirds majority it needed. Voting closed on June 3, 2026, and the implementation has been merged and ships in PHP 8.6.

Summary

If your code has many network connections open, you need a way to find out which ones have data ready. In PHP, the only tool for that has been stream_select(), which is slow with lots of connections and often tops out at 1024 of them. This RFC from Jakub Zelenka adds a new polling API to PHP that uses the fastest mechanism each system offers, like epoll on Linux and kqueue on macOS.

Why add it

The main goal is a shared polling layer inside PHP itself that PHP-FPM, signal handling and extensions like curl and sockets can all use. Exposing it to PHP code is a bonus. Async libraries like AMPHP, ReactPHP and Revolt could rely on one fast backend instead of maintaining several. It isn't a full event loop, just the polling part.

How it works

The new classes live in the Io\Poll namespace. You create a Context, add the streams you want to watch, then call wait(). Here's a trimmed version of the RFC's server example:

use Io\Poll\{Context, Event};

$poll = new Context();

$server = stream_socket_server('tcp://0.0.0.0:8080', $errno, $errstr);
stream_set_blocking($server, false);

$serverHandle = new StreamPollHandle($server);
$poll->add($serverHandle, [Event::Read], ['type' => 'server']);

while (true) {
    // Returns array of Watcher instances that have events
    $watchers = $poll->wait(1);

    foreach ($watchers as $watcher) {
        if ($watcher->hasTriggered(Event::Read)) {
            // accept a client, or read from one
        }
    }
}

Here are the main pieces:

  • Context holds everything you're watching and picks the best backend for your system automatically.
  • Watcher is what add() returns. You can check its events, modify them, or remove it.
  • StreamPollHandle wraps a stream so it can be watched. Only built-in classes can act as handles.
  • Event is an enum with cases like Read, Write, Error and HangUp. OneShot removes a watcher after it fires once, and EdgeTriggered only reports state changes, on epoll and kqueue.

The supported backends are epoll (Linux), kqueue (BSD, macOS), event ports (Solaris, illumos), WSAPoll (Windows), and poll as a fallback.

What it means for existing code

Nothing breaks, since the RFC only adds new code. It does introduce a new Io namespace. The author found one active project on GitHub that uses Io, and it doesn't clash with Io\Poll.