lawoole/swoole
Lawoole Swoole integration for Laravel, adding a coroutine-based server runtime and high-concurrency request handling as an alternative to PHP-FPM. Small, early-stage project with limited adoption and maintenance activity.
This package is best understood as an API reference/stub layer for Swoole inside a Laravel/Lawoole application, not a runtime framework. It will not make Swoole work on its own — the swoole PHP extension must already be installed, enabled, and version-matched. Treat installation as two separate steps:
# 1. Runtime prerequisite (CLI SAPI only)
pecl install swoole
php -m | grep swoole
# 2. The reference package
composer require lawoole/swoole
Then look at, in this order:
composer.json — check the autoload block. If it maps a Lawoole\Swoole\ namespace to src/, import from there. If it only ships stubs/aliases, your IDE and static analyser are the primary consumers.src/ — most likely contains class aliases, IDE helper docblocks, or constants mirroring Swoole\*. Skim for Swoole\Coroutine, Swoole\Http\Server, and Swoole\WebSocket\Server references; those are the surfaces you will touch daily.First real use case: wiring a Swoole HTTP/WebSocket server entry point alongside your normal Laravel bootstrap so you get autocompletion and type hints on $request, $response, and $server inside coroutine callbacks:
use Swoole\Http\Request;
use Swoole\Http\Response;
$server->on('request', function (Request $req, Response $res) {
$res->header('Content-Type', 'application/json');
$res->end(json_encode(['ok' => true]));
});
If your IDE resolves those types after composer require, the package is doing its job.
Use it as a type-hint and autocompletion source, not as application logic. The day-to-day value is in making Swoole's native classes legible inside Laravel-shaped code.
Pattern: bridge Swoole callbacks into container-resolved services. Swoole callbacks run outside the normal request lifecycle, so resolve dependencies explicitly rather than relying on facades that assume app() state:
$server->on('request', function (Request $req, Response $res) use ($app) {
$handler = $app->make(MyRequestHandler::class);
$res->end($handler->handle($req));
});
Pattern: coroutine-scoped work. Where the package documents or aliases coroutine helpers, prefer explicit Co::run() / go() scopes over sprinkling raw swoole_* functions, so you can swap the implementation in tests:
use Swoole\Coroutine as Co;
Co::run(function () {
$channel = new Co\Channel(1);
go(fn () => $channel->push(doWork()));
$result = $channel->pop();
});
Pattern: static analysis. Add the package's stubs to PHPStan/Psalm bootstrap paths so CI stops complaining about undefined Swoole\* symbols:
# phpstan.neon
parameters:
scanFiles:
- vendor/lawoole/swoole/stubs/Swoole.php
(Confirm the actual stub path in vendor/lawoole/swoole/ — this is the one path you should verify rather than guess.)
Pattern: keep framework code coroutine-agnostic. Don't let Lawoole\Swoole types leak into domain classes. Isolate Swoole in an adapter layer (a Server wrapper, a Request mapper) so the bulk of your app stays testable outside a coroutine context.
Integration tip: when mixing with Laravel's queue/event system, remember Swoole workers persist across requests. Any singleton registered in the container survives — which is usually desired, but only if it holds no per-request mutable state.
php -m shows swoole in FPM but your artisan command fails, you are testing the wrong binary. Verify with php -r 'var_dump(extension_loaded("swoole"));' from the same CLI you run the server with.app() singletons, and globals shared across coroutines cause the classic "user A sees user B's data" bug. Audit any singleton that mutates state per request.on('request', ...) often die without a stack trace reaching your Laravel log. Wrap the body in try/catch and log explicitly to a Swoole-safe logger.Swoole\Coroutine::getCid() (returns -1 outside a coroutine) is your fastest sanity check that code is running where you think it is. Pair with Swoole\Coroutine::getBackTrace() when a coroutine hangs.swoole.use_shortname = Off in php.ini forces you to use namespaced classes, which makes the stubs more useful and the intent clearer.php artisan vendor:publish) and commit the result — you will want to patch signatures locally when the upstream stubs lag the extension.How can I help you explore Laravel packages today?