themattosdev / leakless
Zero state and memory leak prevention for PHP persistent runtimes (FrankenPHP & Laravel Octane)
Requires
- php: ^8.2
Requires (Dev)
- laravel/pint: ^1.18
- nunomaduro/phpinsights: ^2.11 || ^2.14
- nyholm/psr7: ^1.8
- orchestra/testbench: ^9.0 || ^10.0
- pestphp/pest: ^3.0
- pestphp/pest-plugin-arch: ^3.0
- phpstan/phpstan: ^2.0
- psr/http-server-middleware: ^1.0
- themattosdev/leakless-dev: *@dev
Suggests
- ext-posix: Used to dynamically detect custom OS kernel memory page sizes (defaults to 4096 bytes)
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-09-10 18:15:17 UTC
README
Zero-State & Memory Leak Prevention for Persistent PHP Workers (FrankenPHP, RoadRunner, Swoole, Symfony, Laravel & Vanilla)
Overview
In traditional PHP-FPM, worker processes terminate after each request, allowing the OS to wipe memory and state. Persistent runtimes like FrankenPHP, RoadRunner, Swoole, and Laravel Octane keep PHP in memory across thousands of requests. While significantly faster, long-running workers can suffer from unmonitored C-extension memory growth (outside the Zend VM heap), dangling database transactions, open file handles, and polluted global/static state.
Leakless is an autonomous runtime guardian and static analysis engine for any persistent PHP stack: it reads real Linux kernel RSS from /proc/self/statm, rolls back uncommitted PDO transactions, cleans runtime state with a zero-reflection resettables engine in finally blocks, gracefully recycles workers before OOM Killer strikes, and provides static analysis via PHPStan and Pest assertions.
Installation
# Runtime engine (production) composer require themattosdev/leakless # Developer tooling, CLI analyzer, and Pest assertions composer require --dev themattosdev/leakless-dev
Usage
1. Vanilla PHP / FrankenPHP Loop
use TheMattos\Leakless\DTOs\Config; use TheMattos\Leakless\Integrations\FrankenPhp\FrankenPhp; FrankenPHP::run( app: function () { echo json_encode(['status' => 'ok']); }, config: new Config( maxDriftMb: 64, maxRequests: 1000, resettables: [ App\Services\CartSession::class, fn () => LegacyRegistry::$cache = [], ], ), );
2. Laravel Octane (Zero-Config)
LEAKLESS_ENABLED=true LEAKLESS_MAX_DRIFT_MB=64 LEAKLESS_CHECK_TRANSACTIONS=true LEAKLESS_CHECK_FILE_DESCRIPTORS=false
In config/leakless.php, you can also register classes or callbacks to auto-reset:
'resettables' => [ App\Services\CartSession::class, fn () => LegacyRegistry::$cache = [], ],
Note regarding Laravel Octane: Octane provides native
scoped()bindings and a'flush'list inconfig/octane.php. Leakless provides its compiled zero-reflectionresettablesengine and#[ResetOnRequest]attribute. It is at your own discretion which mechanism to use — you can rely on Octane's native mechanisms, use Leakless's resettables, or combine both seamlessly.
3. Declarative State Reset (#[ResetOnRequest])
Annotate properties or classes to automatically restore initial or default values between requests when registered in resettables:
use TheMattos\Leakless\Attributes\ResetOnRequest; class UserContext { // Static properties are reset when registering UserContext::class in 'resettables' #[ResetOnRequest] public static ?string $token = null; #[ResetOnRequest(default: 'guest')] public static string $role = 'guest'; // Instance properties are reset when registering the object instance itself #[ResetOnRequest(default: [])] public array $permissions = []; }
// In config/leakless.php: 'resettables' => [ // Resets static #[ResetOnRequest] properties and static cleanup methods: UserContext::class, // To reset instance properties, register the resolved object instance or callback: // fn () => app(UserContext::class)->permissions = [], ],
Important:
#[ResetOnRequest]does not automatically scan all classes across your application. To be reset at runtime, the target class (forstaticstate) or object instance (for instance state) must be registered in'resettables'or via$leakless->registerResetTarget().
4. Automated Testing (Pest & PHPUnit)
test('service executes cleanly without leaking memory or state', function () { // 1. Structural design check (no mutable static props or illegal constructor injections) expect(PaymentService::class)->toBeLeakless(); // 2. Full request lifecycle check (PDO transactions, FDs, and Linux RSS drift) expect(function () { (new PaymentService())->processPendingTransactions(); })->toRunCleanly(maxDriftMb: 0.25); // 3. Deep container/instance property snapshotting (detects runtime state mutations) expect(app())->toResetContainerState(function () { $this->postJson('/api/checkout', ['item' => 'pro']); }); });
5. Static Worker Linter CLI
vendor/bin/leakless analyze
Documentation
Full documentation, architecture guides, kernel memory details, and anti-pattern catalogues are available at:
👉 https://leakless.themattos.dev
Testing & Quality
# Run test suite docker compose run --rm app vendor/bin/pest # Code style docker compose run --rm app vendor/bin/pint --test # Static analysis (Level 9) docker compose run --rm app composer analyse
License
Open-source software licensed under the MIT License.
Developed by Jonathan Gonçalves.
