Skip to content

Runtimes & frameworks

Runtime --runtime value
FrankenPHP worker mode frankenphp
Laravel Octane octane
RoadRunner roadrunner
Swoole / OpenSwoole swoole

Worker Safety does not detect which runtime your application uses. There is no such check anywhere in the tool, and the report labels the list Analysis targets for that reason: it is the set of runtimes the scan reasons about, chosen by you with --runtime (default: all four).

Nor is the absence of a runtime package in composer.json treated as evidence that no persistent worker is involved. It is not reliable evidence: a runtime can be installed outside Composer — FrankenPHP and RoadRunner are binaries — the decision usually lives in deployment configuration the source tree never sees, and a long-running queue worker holds process state across jobs without any of these packages being present.

That last point is a reason not to trust the inference, not a claim of support: queue workers are not an analysis target, --runtime has no value for them, and no rule models a job lifecycle. The four runtimes in the table above are the whole list.

The practical consequence is that nothing is hidden or downgraded because a runtime looks absent. That is deliberate: the most useful moment to run this tool is before the migration, when none of those packages are installed yet. Findings are conditional statements — what this code would do if it ran under a persistent worker — and reading them is still your job.

All four are analyzed by default. Selecting a subset narrows which rules run and which runtimes each finding lists, and when exactly one runtime is selected the console report adds that runtime’s specific caveat — for example, that Octane resets container state between requests but never your own statics. Note that octane.flush does not help there: it calls forgetInstance() on the container bindings you list and never touches a static property, so a static needs an explicit reset from a RequestReceived or RequestTerminated listener.

Superglobals differ per runtime too. FrankenPHP worker mode resets $_GET, $_POST, $_COOKIE, $_FILES, $_SERVER and $_REQUEST between requests and documents $_ENV as the exception, which is why WS003 rates a $_ENV write above a $_SERVER one.

Framework Detection Support
Laravel laravel/framework, laravel/lumen-framework, illuminate/support Container-binding analysis (WS005, WS006), Laravel-aware event detection in WS009, framework-specific scan defaults.
Symfony symfony/framework-bundle, symfony/symfony Scan defaults. The adapter is a ready extension point; v1 ships no Symfony-specific rules rather than guessing.
Plain PHP fallback All eight framework-independent rules.

Detection is a read of composer.json and composer.lock. The framework itself is never installed, loaded or booted, and Worker Safety does not depend on it.

A scoped() registration only silences WS005/WS006 when it uses the exact same container key. Keys are plain array keys, so 'Shared' is not 'shared', and aliases are deliberately not followed: forgetScopedInstances() unsets $instances[$key] without resolving aliases, and bind() deletes the alias for any key it re-registers — so alias(Ctx::class, 'a') plus scoped('a') leaves the Ctx::class singleton alive. This key identity is separate from PHP class-name identity, which stays case-insensitive when resolving a bound class to its declaration.