PHPackages                             phpdot/server-swoole - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [HTTP &amp; Networking](/categories/http)
4. /
5. phpdot/server-swoole

ActiveLibrary[HTTP &amp; Networking](/categories/http)

phpdot/server-swoole
====================

Swoole HTTP server adapter for PSR-15. Framework-agnostic.

v2.7.0(2mo ago)018MITPHPPHP &gt;=8.3

Since Apr 1Pushed 2w agoCompare

[ Source](https://github.com/phpdot/server-swoole)[ Packagist](https://packagist.org/packages/phpdot/server-swoole)[ RSS](/packages/phpdot-server-swoole/feed)WikiDiscussions main Synced 4w ago

READMEChangelogDependencies (20)Versions (17)Used By (0)

phpdot/server-swoole
====================

[](#phpdotserver-swoole)

Swoole HTTP/WebSocket server adapter for PSR-15. Framework-agnostic, standalone, full Swoole coverage.

Install
-------

[](#install)

```
composer require phpdot/server-swoole
```

Requires `ext-swoole >= 6.0` and PHP 8.3+.

Quick Start
-----------

[](#quick-start)

```
use Nyholm\Psr7\Factory\Psr17Factory;
use PHPdot\Server\Swoole\SwooleServer;
use PHPdot\Server\Swoole\Config\ServerConfig;

$factory = new Psr17Factory();
$config = new ServerConfig(workerNum: 4);

$server = new SwooleServer($factory, $config);
$server->serve($handler, '0.0.0.0', 8080);
```

`$handler` is any PSR-15 `RequestHandlerInterface` -- your router, your framework, your middleware pipeline.

---

Server Configuration
--------------------

[](#server-configuration)

`ServerConfig` is a simple readonly data class. No static methods, no builders -- just named constructor parameters:

```
$config = new ServerConfig(
    workerNum: 8,
    maxRequest: 50000,
    daemonize: true,
    pidFile: '/var/run/app.pid',
    logFile: '/var/log/app.log',
);
```

### Workers &amp; Process

[](#workers--process)

```
$config = new ServerConfig(
    workerNum: 8,              // worker processes (default: CPU count)
    taskWorkerNum: 4,          // task workers (default: 0)
    maxRequest: 100000,        // restart worker after N requests
    maxCoroutine: 100000,      // max coroutines per worker
    mode: SWOOLE_PROCESS,      // SWOOLE_PROCESS (default) or SWOOLE_BASE
);
```

### SSL / HTTPS

[](#ssl--https)

```
$config = new ServerConfig(
    sockType: SWOOLE_SOCK_TCP | SWOOLE_SSL,
    sslCertFile: '/etc/ssl/certs/app.pem',
    sslKeyFile: '/etc/ssl/private/app.key',
    http2: true,
);

$server->serve($handler, '0.0.0.0', 443);
```

### Static Files

[](#static-files)

```
$config = new ServerConfig(
    staticHandler: true,
    documentRoot: '/var/www/public',
    staticHandlerLocations: ['/assets', '/images', '/favicon.ico'],
);
```

Static file requests bypass PHP entirely -- served directly by Swoole's kernel.

### Compression

[](#compression)

```
$config = new ServerConfig(
    httpCompression: true,          // enabled by default
    httpCompressionLevel: 3,        // 1-9 (default: 1)
    httpCompressionMinLength: 20,   // min bytes to compress (default: 20)
);
```

### Raw Swoole Settings

[](#raw-swoole-settings)

For any Swoole setting not covered by typed properties:

```
$config = new ServerConfig(
    workerNum: 4,
    rawSettings: [
        'dispatch_mode' => 2,
        'reload_async' => true,
    ],
);
```

Typed properties always take precedence over `rawSettings`.

### Inside the phpdot framework

[](#inside-the-phpdot-framework)

`ServerConfig` carries `#[Config('server')]`, so when used with `phpdot/package` it's auto-hydrated from `config/server.php`:

```
// config/server.php
return [
    'workerNum'  => 4,
    'maxRequest' => 10000,
    'daemonize'  => false,
    // ... any ServerConfig property
];
```

The container resolves `ServerConfig` automatically — no manual `new ServerConfig(...)` needed when running inside the framework. Standalone consumers (no `phpdot/package`) instantiate `ServerConfig` directly via the constructor as shown above.

`SwooleServer` itself isn't auto-wired (its constructor uses an intersection type for the PSR-17 factory, which PHP-DI can't autowire). Register it manually in your application boot:

```
$builder->register(
    SwooleServer::class,
    new ScopedDefinition(
        scope: Scope::SINGLETON,
        factory: static fn (ContainerInterface $c): SwooleServer => new SwooleServer(
            $c->get(\PHPdot\Http\ResponseFactory::class),  // satisfies all 4 PSR-17 factory interfaces
            $c->get(ServerConfig::class),
        ),
    ),
);
```

For per-coroutine scoping of `Scope::SCOPED` services (the standard pattern under Swoole), install `phpdot/container-swoole` and register its provider:

```
$builder->withContextProvider(new SwooleContextProvider());
```

---

Event Callbacks
---------------

[](#event-callbacks)

Register callbacks directly on the server. Multiple callbacks per event -- they stack, never replace:

```
$server = new SwooleServer($factory, $config);

// Lifecycle
$server->onStart(function (Server $server): void {
    cli_set_process_title('app: master');
});

$server->onWorkerStart(function (Server $server, int $workerId): void {
    cli_set_process_title("app: worker {$workerId}");
});

$server->onShutdown(function (Server $server): void {
    echo "Server stopped\n";
});
```

### Available Events

[](#available-events)

CategoryEventsLifecycle`onStart`, `onManagerStart`, `onManagerStop`, `onWorkerStart`, `onWorkerStop`, `onWorkerExit`, `onWorkerError`, `onBeforeShutdown`, `onShutdown`, `onBeforeReload`, `onAfterReload`Connection`onConnect`, `onClose`Task`onTask`, `onFinish`IPC`onPipeMessage`WebSocket`onOpen`, `onMessage`, `onHandshake`, `onDisconnect`---

WebSocket
---------

[](#websocket)

When any WebSocket callback is registered, the server automatically creates a `WebSocket\Server` instead of `Http\Server`. HTTP and WebSocket work on the same port:

```
$server->onOpen(function (WebSocketServer $server, Request $request): void {
    echo "Client connected: {$request->fd}\n";
});

$server->onMessage(function (WebSocketServer $server, Frame $frame): void {
    $server->push($frame->fd, "Echo: {$frame->data}");
});

$server->onClose(function (Server $server, int $fd): void {
    echo "Client disconnected: {$fd}\n";
});

$server->serve($handler, '0.0.0.0', 8080);
```

### Active WebSocket Methods

[](#active-websocket-methods)

Push messages and manage connections from anywhere in your application:

```
$server->push($fd, $data);              // send data to a client
$server->wsDisconnect($fd);             // disconnect a client
$server->isEstablished($fd);            // check if connection is active
```

---

Task Workers
------------

[](#task-workers)

Offload heavy work to task worker processes:

```
$server = new SwooleServer($factory, new ServerConfig(taskWorkerNum: 4));

$server->onTask(function (Server $server, Task $task): void {
    // runs in a task worker process
    $result = processHeavyWork($task->data);
    $task->finish($result);
});

$server->onFinish(function (Server $server, int $taskId, mixed $data): void {
    // result returned to the requesting worker
});

// dispatch from anywhere after serve()
$server->task($data);                          // async dispatch
$server->taskCo([$data1, $data2], timeout: 1); // coroutine dispatch, wait for results
$server->finish($result);                      // return result from task worker
```

---

Timers
------

[](#timers)

Set recurring or one-shot timers:

```
$timerId = $server->tick(5000, function (): void {
    // runs every 5 seconds
});

$server->after(10000, function (): void {
    // runs once after 10 seconds
});

$server->clearTimer($timerId);
```

---

Connection Management
---------------------

[](#connection-management)

```
$server->exists($fd);                     // check if connection exists
$server->close($fd);                      // close a connection
$server->getClientInfo($fd);              // get connection details
$server->getClientList();                 // list connected file descriptors
$server->sendMessage($data, $workerId);   // send message to another worker
```

---

Server Info &amp; Lifecycle
---------------------------

[](#server-info--lifecycle)

```
// info
$server->stats();
$server->getWorkerId();
$server->getWorkerPid();
$server->getWorkerStatus();
$server->getMasterPid();
$server->getManagerPid();

// lifecycle
$server->shutdown();
$server->reload();
$server->stop($workerId);
```

---

Escape Hatch
------------

[](#escape-hatch)

For advanced Swoole features not directly exposed (addProcess, addListener, bind, protect, etc.):

```
$swoole = $server->getServer();
$swoole->addProcess(new Process(function () { /* ... */ }));
```

---

Streaming (CallbackStreamInterface)
-----------------------------------

[](#streaming-callbackstreaminterface)

For real-time streaming (SSE, chunked responses), implement `CallbackStreamInterface`:

```
use PHPdot\Server\Swoole\CallbackStreamInterface;

final class SseStream implements StreamInterface, CallbackStreamInterface
{
    public function __construct(private readonly Closure $producer) {}

    public function getCallback(): Closure
    {
        return function (Closure $write): void {
            ($this->producer)($write);
        };
    }
}
```

The `ResponseConverter` detects this interface and streams each chunk directly via `$swooleResponse->write()` -- data reaches the client immediately without buffering.

---

Architecture
------------

[](#architecture)

 ```
flowchart TB
    Client(["Client"])
    Server["Swoole HTTP / WS Server"]
    ReqConv["RequestConverterSwoole → PSR-7headers, URI, body, cookies, files"]
    Handler["Your PSR-15 Handlerrouter, middleware, controllers"]
    ResConv["ResponseConverterPSR-7 → Swoolesendfile, chunked, streaming"]

    Client --> Server
    Server -- "Swoole\Http\Request" --> ReqConv
    ReqConv -- "ServerRequestInterface" --> Handler
    Handler -- "ResponseInterface" --> ResConv
    ResConv -- "Swoole\Http\Response" --> Server
    Server --> Client
```

      Loading ### Response Emission Strategies

[](#response-emission-strategies)

The `ResponseConverter` selects the optimal strategy for each response:

StrategyWhenHowCallbackStreamBody implements `CallbackStreamInterface``write()` per chunk -- true streamingSendfileBody is a plain file stream`sendfile()` -- zero-copy kernel transferEmptyBody size is 0`end()` -- no bodyChunkedBody exceeds chunk threshold (default 1 MB)`write()` in chunksDirectEverything else`end($body)` -- single write---

Production Example
------------------

[](#production-example)

```
$config = new ServerConfig(
    workerNum: 8,
    taskWorkerNum: 2,
    maxRequest: 100000,
    daemonize: true,
    pidFile: '/var/run/app.pid',
    logFile: '/var/log/app.log',
    logLevel: SWOOLE_LOG_WARNING,
    sockType: SWOOLE_SOCK_TCP | SWOOLE_SSL,
    sslCertFile: '/etc/ssl/certs/app.pem',
    sslKeyFile: '/etc/ssl/private/app.key',
    http2: true,
    httpCompression: true,
    staticHandler: true,
    documentRoot: '/var/www/public',
);

$server = new SwooleServer($factory, $config);

$server->onWorkerStart(function (Server $server, int $workerId): void {
    cli_set_process_title("app: worker {$workerId}");
});

$server->serve($handler, '0.0.0.0', 443);
```

---

Package Structure
-----------------

[](#package-structure)

```
src/
  SwooleServer.php                Main entry point -- events, active methods, lifecycle
  CallbackStreamInterface.php     Streaming contract
  Config/
    ServerConfig.php              Readonly server configuration
  Converter/
    RequestConverter.php          Swoole -> PSR-7
    ResponseConverter.php         PSR-7 -> Swoole
  Exception/
    ServerException.php           Server errors

```

PSR Standards
-------------

[](#psr-standards)

PSRUsagePSR-7`ServerRequestInterface`, `ResponseInterface` -- the bridge formatPSR-15`RequestHandlerInterface` -- your application entry pointPSR-17All 4 factories -- builds PSR-7 objects from Swoole dataDevelopment
-----------

[](#development)

```
composer test        # PHPUnit
composer analyse     # PHPStan level 10
composer cs-fix      # PHP-CS-Fixer
composer check       # All three
```

License
-------

[](#license)

MIT

###  Health Score

43

—

FairBetter than 90% of packages

Maintenance93

Actively maintained with recent releases

Popularity6

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity57

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~2 days

Total

16

Last Release

63d ago

Major Versions

v1.0.2 → v2.0.02026-04-14

### Community

Maintainers

![](https://www.gravatar.com/avatar/62e82421bda4b5d6ba9a47ba6d88caca060dcd0d1a2862f351f3a97657385db0?d=identicon)[phpdot](/maintainers/phpdot)

---

Top Contributors

[![phpdot](https://avatars.githubusercontent.com/u/252500?v=4)](https://github.com/phpdot "phpdot (16 commits)")

---

Tags

httppsr-7asyncserverpsr-15swoole

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/phpdot-server-swoole/health.svg)

```
[![Health](https://phpackages.com/badges/phpdot-server-swoole/health.svg)](https://phpackages.com/packages/phpdot-server-swoole)
```

###  Alternatives

[guzzlehttp/psr7

PSR-7 message implementation that also provides common utility methods

8.0k1.1B3.9k](/packages/guzzlehttp-psr7)[cakephp/cakephp

The CakePHP framework

8.9k19.5M1.8k](/packages/cakephp-cakephp)[mezzio/mezzio

PSR-15 Middleware Microframework

3923.8M121](/packages/mezzio-mezzio)[tempest/framework

The PHP framework that gets out of your way.

2.2k34.4k13](/packages/tempest-framework)[sunrise/http-router

A powerful solution as the foundation of your project.

17450.9k10](/packages/sunrise-http-router)[laminas/laminas-stratigility

PSR-7 middleware foundation for building and dispatching middleware pipelines

587.2M98](/packages/laminas-laminas-stratigility)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
