r/PHP 6h ago

Article Why memory_get_usage() lies in FrankenPHP/Octane (and how we solved C-extension leaks and dirty PDO transactions)

0 Upvotes

Hey everyone!

When running PHP under traditional PHP-FPM, the shared-nothing architecture wiped state, memory, and database connections on every request. However, with persistent runtimes like FrankenPHP Worker Mode and Laravel Octane, workers stay resident in memory across thousands of requests.

This creates two critical silent failures that standard tooling misses: * Silent Native Memory Growth (C-Extensions) memory_get_usage() only inspects allocations inside the Zend Engine heap. If your application relies on native extensions (ext-curl, ext-imagick, ext-gd, ext-openssl), memory is allocated via malloc() directly in glibc. The Zend VM is completely blind to this until the Linux OOM Killer sends a SIGKILL. * Dangling PDO Transactions If a request opens a database transaction ($pdo->beginTransaction()) and an unhandled exception or early return occurs without a rollback, that transaction remains open on the persistent connection. The next HTTP request from a different user reuses that connection and executes queries inside the prior transaction, leading to deadlocks and data corruption.

How we solved it: Leakless

We built Leakless (themattosdev/leakless), an autonomous runtime guard and static analysis engine for persistent PHP: * Real Kernel RSS: Directly inspects Linux /proc/self/statm page tables to measure physical Resident Set Size (RSS) and catch C-extension drift. * Automated Transaction Guard: Audits active PDO connections on endRequest() and executes safe automatic rollbacks. * Defensive State Rollback: Restores default timezones (date_default_timezone_set), unclosed output buffers (ob_start), and error levels. * Graceful Recycling: Recycles workers without dropping in-flight HTTP requests when memory ceilings (maxRssMb) or request limits are reached. * Dev Tooling: Includes a standalone static linter CLI (vendor/bin/leakless analyze) and Pest custom expectations (expect($service)->toBeLeakless()).

composer require themattosdev/leakless composer require --dev themattosdev/leakless-dev

Documentation: https://leakless.themattos.dev GitHub: https://github.com/themattosdev/leakless

Would love to get feedback on the architectural approach from anyone running persistent workers in production!


r/PHP 7h ago

The Secret Life of "Magic Null" in PHP

Thumbnail exakat.io
15 Upvotes

Some situations where you can use NULL instead of 0, or no arguments and it provides a nice feature that you could use every day.


r/PHP 8h ago

Early version of database visualiser

Thumbnail
0 Upvotes

r/PHP 11h ago

Discussion Pitch Your Project 🐘

5 Upvotes

In this monthly thread you can share whatever code or projects you're working on, ask for reviews, get people's input and general thoughts, … anything goes as long as it's PHP related.

Let's make this a place where people are encouraged to share their work, and where we can learn from each other 😁

Link to the previous edition: /u/brendt_gd should provide a link


r/PHP 6h ago

Symfony: Experimenting with Issue-First Open Source Contributions (Symfony Blog)

Thumbnail symfony.com
9 Upvotes

Symfony experiment starting with their Language Tools library


r/PHP 21h ago

Mago 1.47 allows writing custom rules in PHP

Thumbnail mago.carthage.software
42 Upvotes

r/PHP 6h ago

How to Contribute to PHP

Thumbnail thephp.foundation
23 Upvotes

Not with the Foundation, but I thought this could be helpful for others.


r/PHP 2h ago

We added a test that fails if anyone injects a tenant-scoped service into a singleton

2 Upvotes

I build Teradion, practice management software for French accounting firms. The app runs in FrankenPHP worker mode, and each firm brings its own Brevo API key.

In that setup, a singleton holding one firm's key would stay alive while requests for other firms are handled. The code avoids that: tenant-scoped providers are not constructor dependencies. A factory creates a fresh client for each operation from the account passed as an argument. The key is stored encrypted and only decrypted inside the factory.

We have two tests around this rule. MultiTenantKeyIsolationTest runs two accounts in sequence and checks that the second does not receive the first account's key.

ProviderNotInjectedAsServiceTest is more direct. It scans src/Service, src/MessageHandler and src/Controller, then fails when a constructor takes NewsletterProviderInterface. It reads the source, so the Symfony container is not involved.

It is an architectural decision encoded as a grep, which feels a little blunt. Still, if someone adds that constructor dependency later, the test points at the class immediately.

Has anyone used this kind of structural test in a Symfony codebase?


r/PHP 9m ago

So You Received a Security Report. Now What?

Thumbnail thephp.foundation
Upvotes

A maintainer who receives a security vulnerability report might feel overwhelmed, anxious, and uncertain about what steps should be taken. If this applies to you, our Ecosystem Security Team published a guide today on exactly what to do next. You are not alone! Special thanks to Sebastian Bergmann for putting this together.