The PHP RFC that defines a native Polling API has been approved and merged into the language’s master branch, giving developers a fast, OS-level way to poll file descriptors. Coupled with the recently added Fibers, PHP now has a built-in, efficient foundation for asynchronous code—a gap that has long forced libraries to cobble together their own work-arounds.

Fibers and the event loop, separated

Fibers are a low-level control-flow primitive. They let a function suspend its execution at a chosen point and later resume exactly where it left off. Crucially, a fiber knows nothing about sockets, timers or any other I/O source; it simply pauses and restarts on demand.

An event loop is the scheduler that decides when a paused fiber should be resumed. In a typical async stack the loop watches a set of file descriptors, waits for them to become readable or writable, and then wakes the appropriate fiber.

PHP previously had Fibers but lacked a native mechanism to ask the operating system which descriptors were ready. The result was a reliance on stream_select() or external extensions, and every async library ended up writing its own back-ends for Linux’s epoll, BSD’s kqueue, Windows’ IOCP, etc.

The new Polling API fills that missing piece. It exposes a thin wrapper around the OS’s polling facilities (epoll on Linux, kqueue on BSD/macOS, etc.). The API does not replace Fibers; it simply gives the event loop the speed and scalability it needs.

Why the change matters for ReactPHP, Amp and friends

ReactPHP and Amp v3 have built their own abstraction layers over the OS polling mechanisms. Those layers contain multiple code paths, each tuned for a specific platform, and they must be kept in sync with kernel changes. With a native Polling API, the libraries can drop most of that plumbing and rely on a single, core-provided call.

  • Maintenance – Fewer platform-specific branches mean fewer bugs and a smaller surface area for security reviews.
  • Performance – The native call talks directly to epoll/kqueue.
  • Portability – Code that runs on “vanilla” PHP now gets the same baseline performance on all supported operating systems, without the need for optional extensions.

Swoole, by contrast, remains a full-runtime replacement that ships its own event loop and coroutine system. The Polling API does not affect Swoole’s trade-offs; developers who need ultra-low latency or custom memory management will still consider it a separate option.

A quick benchmark tells the story

A minimal scheduler fetched several URLs over raw sockets, using a single Io\Poll\Context to manage multiple fibers. Two observations emerged:

  1. Speed – Adding more concurrent requests does not increase total elapsed time; the request batch finishes as quickly as the slowest single request. In other words, the concurrency overhead is effectively zero.
  2. CPU cost – With stream_select() the CPU usage climbs noticeably as the number of streams grows, because the function must iterate over every descriptor on each call. The Polling API’s cost stays flat from three streams to thirty, thanks to the kernel’s ability to monitor many descriptors in a single system call.

What developers should do now

  • Adopt Amp v3 if you prefer a fiber-native style that aligns directly with the new API. Its public interface already maps to the underlying poller, so you get the benefit without rewriting your code.
  • Stick with ReactPHP if you like explicit control over the loop’s lifecycle.
  • Avoid custom schedulers for production workloads. Do not write your own scheduler for production.