Skip to content

Attributes & Diagnostic Reports ​

This section covers how to interact with the diagnostic reports and attributes exposed by Leakless.


1. Inspecting the Report Object ​

At the end of every request cycle, $leakless->endRequest() returns a Report object containing diagnostic data and memory metrics.

Practical Usage Example ​

php
$report = $leakless->endRequest();

// 1. Check if the request executed cleanly
if (! $report->isClean()) {
    logger()->warning('Worker state anomaly detected in request');
}

// 2. Check if open database transactions were intercepted and rolled back
if ($report->danglingTransactionsDetected) {
    // Send metric to Prometheus, Datadog, or Sentry
    metrics()->increment('worker.transactions.rolled_back');
}

// 3. Inspect real Linux kernel RSS memory metrics
echo "Physical memory consumed in this request: {$report->memoryDriftMb} MB\n";
echo "Current worker resident memory (RSS): {$report->finalMetrics->rssMb} MB\n";

// 4. In ZTS mode, inspect thread attribution
if ($report->isZts) {
    if ($report->unattributedProcessDrift) {
        logger()->warning('Process RSS drifted without current thread Zend MM growth (noisy neighbor or native leak)');
    }
}

// 5. Check if worker reached memory ceilings or request limits
if ($report->shouldRecycle) {
    // Gracefully terminate or signal process manager
    $worker->stop();
}

Available Properties & Methods ​

Property / MethodTypeDescription
$report->isClean()boolMethod: returns true if no transactions leaked, no FDs leaked, and no recycling was triggered.
$report->danglingTransactionsDetectedbooltrue if one or more open PDO transactions were rolled back.
$report->danglingTransactionsCountintNumber of uncommitted PDO transactions intercepted and rolled back.
$report->fileDescriptorsLeakedbooltrue if lingering file handles or open sockets were detected.
$report->fileDescriptorsLeakedCountintCount of unclosed file descriptors left behind.
$report->fileDescriptorsLeakedMaparray<int, string>Map of leaked descriptors [fd => targetPath].
$report->shouldRecyclebooltrue if memory drift, emergency ceiling, or request count limits were breached.
$report->recycleReasonstring|nullHuman-readable explanation if worker recycling was triggered.
$report->memoryDriftMbfloatPhysical RSS delta ($\Delta\text{RSS}$) in megabytes during the request.
$report->zendMemoryDriftMbfloatDelta in current thread Zend Memory Manager during the request.
$report->driftOverBaselineMbfloatCumulative process memory drift above the worker baseline RSS.
$report->initialMetricsProcessMetricsSnapshot of process memory before request handling.
$report->finalMetricsProcessMetricsSnapshot of process memory after request handling.
$report->isZtsbooltrue if the runtime is operating in Zend Thread Safety (ZTS) multithread mode.
$report->driftAttributedToThreadboolIn ZTS mode: true if process drift was confirmed by the active thread's Zend memory growth.
$report->unattributedProcessDriftboolIn ZTS mode: true if process RSS drifted without current thread Zend memory growth.
$report->consecutiveViolationsCountintCurrent count of consecutive drift breaches.
$report->cooldownActivebooltrue if recycling was throttled due to cooldown window.

2. Process Memory Metrics (ProcessMetrics) ​

The $report->initialMetrics and $report->finalMetrics properties contain Linux kernel memory details:

php
$metrics = $report->finalMetrics;


// Real physical RAM in MB (Resident Set Size)
$rssMb = $metrics->rssMb;

// Total virtual memory size in MB
$virtualMb = $metrics->sizeMb;

// Raw kernel page counts
$residentPages = $metrics->residentPages;

3. The #[AllowPersistentState] Attribute ​

Use this attribute to declare intentional, thread-safe static caches so they are excluded from static analysis and reflection warnings:

php
use TheMattos\Leakless\Attributes\AllowPersistentState;

class DatabaseSchemaRegistry
{
    // Explicitly permitted: thread-safe immutable boot metadata
    #[AllowPersistentState]
    public static array $tableDefinitions = [];
}

4. The #[ResetOnRequest] Attribute ​

Use this attribute on classes, properties, or methods to declare state that must be automatically reset to initial default values at the end of every request cycle when registered in Leakless's resettables engine:

php
use TheMattos\Leakless\Attributes\ResetOnRequest;

class UserSessionContext
{
    // Restores default value null (static property: reset via class string registration)
    #[ResetOnRequest]
    public static ?string $activeToken = null;

    // Calls custom cleanup method on request completion
    #[ResetOnRequest(resetter: 'cleanup')]
    public static array $inMemoryEvents = [];

    // Restores default value [] (instance property: reset via object instance registration)
    #[ResetOnRequest(default: [])]
    public array $permissions = [];

    public static function cleanup(): void
    {
        self::$inMemoryEvents = [];
    }
}

Supported Targets and Parameters ​

ParameterTypeDefaultDescription
resetterstring|nullnullName of a custom method on the target to invoke on reset.
defaultmixednullExplicit fallback value to assign to the property on reset.
Attribute TargetsProperty, Class, Method—Can be placed directly on static/instance properties, classes, or cleanup methods.

How ResetOnRequest Works at Runtime ​

Registration Requirement

#[ResetOnRequest] does not perform global file or class scanning. It acts as a set of compiled reset rules for targets explicitly registered in the resettables engine:

  • In Laravel: add targets to 'resettables' in config/leakless.php.
  • In Symfony/Vanilla: register targets via Config::$resettables or $leakless->registerResetTarget($target).

Static vs. Instance Properties ​

Registration TypeExampleWhat Gets Reset
Class StringUserSessionContext::classStatic properties annotated with #[ResetOnRequest] and static cleanup methods (or conventional static resetState / cleanup methods). Instance properties are ignored because no instance exists.
Object Instance$userSessionContextInstance properties annotated with #[ResetOnRequest], instance cleanup methods, and conventional reset() methods on that specific object.

PHPStan vs. Runtime Execution

The static analysis rule BanMutableStaticPropertiesRule considers static properties annotated with #[ResetOnRequest] as safe. Remember to always add the class to 'resettables' in your configuration, otherwise the property will remain mutated and leak across requests at runtime despite passing static analysis!

Released under the MIT License.