Coroutine extension and server12 min read

Swoole: a coroutine extension and server for PHP

Swoole is a PHP extension that adds an event loop, coroutines and servers for long-lived PHP services. Learn its model, install approach, a minimal HTTP server and the risks of persistent workers.

PHP compatibility and project lifecycle

The README says master is the Swoole 6.3 development branch and supports PHP 8.2–8.5. Which released version supports PHP 8.4, and its maintenance status, is not in the source and is unknown. Verify against the supported-versions page and a php --ri swoole check.

Official sources checked 2026-10-22. Browser lessons on this site run PHP 8.5.

This guide is based only on the official Swoole source repository README. Where the README is silent, this guide says so.

What Swoole is

The README describes Swoole as a PHP extension for building persistent network services and concurrent I/O applications. Its C/C++ core provides an event loop, a coroutine scheduler, servers, clients and protocol implementations. A bundled PHP library adds connection pools, proxies and higher-level utilities. The repository describes itself as a coroutine-based concurrency library for PHP.

Swoole is not a standalone PHP runtime and not a replacement interpreter. It is a compiled extension that is loaded into an ordinary PHP binary, and your code is normal PHP calling Swoole classes. It is also not part of PHP core, and it is not a framework or a CMS. Framework adapters or application servers built on top of it are separate projects and are not covered by this source.

The repository is swoole/swoole-src. A separate project called Open Swoole exists, but the supplied source does not cover it. Do not assume that its APIs, versions or build options match this repository. Check each project's own documentation.

Architecture

The README describes these building blocks:

  • A Reactor watches sockets and other registered file descriptors and dispatches events to callbacks.
  • Servers can run several worker processes to use several CPU cores.
  • Inside one worker, coroutines let other tasks run while one task waits for supported I/O.
  • Task workers give slow jobs a separate execution path so they do not hold up request handling.
  • Swoole\Process, Swoole\Table and atomics cover background processes and shared state between processes.
  • Thread APIs are optional and need a ZTS build of PHP.

The main server classes are Swoole\Server for TCP, UDP and Unix sockets, Swoole\Http\Server for HTTP, Swoole\Coroutine\Http\Server for a coroutine-managed HTTP server, and Swoole\WebSocket\Server for WebSocket. Coroutines start with Swoole\Coroutine\run() and go(). Channel, WaitGroup and Barrier coordinate them.

Coroutines are a concurrency tool, not automatic CPU parallelism. A CPU-heavy loop occupies its worker until it finishes or yields. Swoole\Runtime::enableCoroutine() hooks selected blocking PHP functions, but the README says hooks do not transform arbitrary third-party C library calls. When precise I/O behavior matters, use the explicit coroutine client or Socket APIs.

Execution model: request lifetimes versus persistent workers

In the classic PHP model, each request starts from a clean slate. Variables, static properties and most resources disappear when the request ends.

Swoole workers are long-lived. The README warns that global variables, static state and open resources can survive beyond one request. That changes how you write code:

  • Keep per-request data in local variables or in objects created for the request, not in globals or statics.
  • Do not store user, tenant or session data in process-wide state. A later request handled by the same worker could read it, which is state leakage.
  • Close or recycle connections, and set timeouts on upstream calls.
  • Handle cancellation and failure explicitly.
  • Remember that ordinary PHP variables are not shared between worker processes. Use IPC, Swoole\Table or external storage for shared data.

The first example below deliberately shows a counter that persists inside a worker. Real applications should treat that behavior as a hazard unless the state is intended, bounded and safe to share across requests. Any cleanup you rely on, such as resetting objects after a request, is your responsibility. The README does not describe an automatic per-request reset.

Practical use cases

The README lists HTTP APIs, WebSocket applications, TCP/UDP gateways and services that handle many connections without a separate PHP process per request. Coroutine clients can call upstream TCP and HTTP services without tying up a worker while waiting. The PHP library offers PDO, MySQLi and Redis connection pools. Whether a given database operation yields depends on the driver and hook configuration.

Swoole is a weaker fit for CPU-bound work in a request handler, for code that relies on a fresh process per request, and for libraries that keep hidden global state. The source makes no claim about compatibility with any particular framework or CMS, so that is unknown here.

Installation approach

The README gives two routes. For a released version, install through PECL. To build a checked-out source tree, install PHP development tools and a C/C++ compiler, then run phpize, configure, make and make install. Enable the extension in the php.ini used by the PHP CLI, or load it for a single command with the extension flag. Verify the result with the extension info command.

Run configure with its help option before enabling optional integrations. The README lists options for sockets, OpenSSL, coroutine cURL, PostgreSQL, c-ares DNS, io_uring and threads. TLS, compression and some hooks depend on build options and the environment. The repository contains a Dockerfile, but its contents and any published image tags are not in the supplied source, so this guide does not use or name any image.

PHP 8.4 compatibility

The README says the master branch is the development branch for Swoole 6.3 and currently supports PHP 8.2 to 8.5. It also says that for production you should choose a released version and check the supported-versions page for that version's PHP compatibility and maintenance status. The packet does not say which released version supports PHP 8.4, so that is unknown. Confirm the PHP version with php -v and then confirm that the extension loads. Treat a successful load as a first check, not proof of full compatibility. The learning track stays on PHP 8.4, with PHP 8.5 planned.

Strengths

  • It runs persistent services in PHP, with servers and clients for several protocols.
  • It supports coroutines for concurrent I/O in one worker.
  • It supports multiple worker processes, task workers and shared tables.
  • The license is Apache-2.0, as stated in the README.

Limitations

  • Persistent workers require disciplined state handling.
  • Coroutines do not parallelize CPU work.
  • Hooks cover only selected functions.
  • Optional features depend on build flags, system libraries and branch.
  • Release versions, PHP compatibility per release, maintenance status and benchmark results are not stated in the packet.
  • Lifecycle is recorded as unknown for the reasons above.

Deployment notes

The README does not describe production deployment, process supervision or reverse-proxy setup, so those are unknown here. The examples bind to 127.0.0.1 for local development only. Do not expose a development server publicly. Before any real deployment, read the official documentation and the supported-versions page, pin a released version and review timeouts, worker counts and cleanup behavior. These examples need the PHP CLI, a native extension build and network access to install it. They are not browser exercises.

Examples

The first example is the README's minimal HTTP server, extended with a per-worker counter to make persistence visible. The second runs two coroutines that wait concurrently.

Links

The official repository README links to the documentation, examples, testing guide and supported-versions page.

Practical examples

These examples have not been run in a live environment yet. Commands and versions follow the official documentation linked on this page; check them before relying on them, and report a problem if one does not work.

Minimal Swoole HTTP server with a per-worker counter

Installs the Swoole extension through PECL and runs a small HTTP server bound to 127.0.0.1:9501 with two workers. The counter is process-wide state that survives across requests in one worker, which demonstrates persistent-worker state. Not a browser exercise.

server.php

<?php

declare(strict_types=1);

// Process-wide state: each worker process keeps its own copy and it
// survives between requests. This is intentional here, to show the
// persistent-worker model. Do not keep per-request or per-user data this way.
$requestsSeenByThisWorker = 0;

$server = new Swoole\Http\Server('127.0.0.1', 9501);
$server->set(['worker_num' => 2]);

$server->on('request', static function ($request, $response) use (&$requestsSeenByThisWorker): void {
    $requestsSeenByThisWorker++;
    $response->header('Content-Type', 'text/plain; charset=utf-8');
    $response->end(
        "Hello, Swoole!\n"
        . 'worker pid: ' . getmypid() . "\n"
        . 'requests seen by this worker: ' . $requestsSeenByThisWorker . "\n"
    );
});

$server->start();

Install and run

php -v
pecl install swoole
php -d extension=swoole.so --ri swoole
php -d extension=swoole.so server.php
curl http://127.0.0.1:9501/

Expected behavior

The php -v command shows the PHP version to check against the compatibility notes. The extension info command prints Swoole details if it is loadable. After starting the server, curl (run in a second terminal) prints a greeting, a worker process id and a counter. Repeated requests increase the counter within a worker, and the two workers keep separate counters. Stop the server with Ctrl+C.

Requires the PHP CLI with development tooling, PECL, a compiler toolchain and network access. If you add extension=swoole.so to php.ini, the -d flag is unnecessary. The PECL release's PHP 8.4 support is not stated in the source and must be verified. Request distribution between workers is not specified here.

Two coroutines waiting concurrently

A CLI script that starts two coroutines with go(), each waiting 0.1 seconds with Swoole's coroutine-aware sleep, and collects results through a Channel. Shows cooperative concurrency inside one process. Not a browser exercise.

coroutines.php

<?php

declare(strict_types=1);

use Swoole\Coroutine\Channel;
use Swoole\Coroutine\System;
use function Swoole\Coroutine\go;
use function Swoole\Coroutine\run;

run(function (): void {
    $results = new Channel(2);

    foreach ([1, 2] as $id) {
        go(function () use ($id, $results): void {
            System::sleep(0.1);
            $results->push("task $id done");
        });
    }

    echo $results->pop(), PHP_EOL;
    echo $results->pop(), PHP_EOL;
});

Install and run

php -d extension=swoole.so coroutines.php

Expected behavior

Two lines are printed, one per task, after roughly 0.1 seconds, and the order of the two lines is not guaranteed. While one task waits, the scheduler can run the other.

Requires the Swoole extension to be installed as in the first example. Coroutines provide concurrent I/O, not CPU parallelism. No timing or performance claim is made.