trace key to error_get_last()fatal_error_backtraces is on by default. Fatal errors collected at shutdown
then carry a debug_backtrace()-shaped frame list under trace. The RFC
only populates the key for those fatals, so it is optional; the other four
keys (type, message, file, line) stay required.
A tool whose stub is still the 8.4 shape reports trace as an unknown
offset (InvalidArrayOffset, "expecting file, line, message or type"). That
is the miss this file measures. Access goes through ?? so an honest
optional-key reading does not also have to warn about a missing offset.
Source: vimeo/psalm#11975, phpstan/phpstan-src#6470. Symfony hit the sealed
8.4 shape in symfony/symfony#66145.
References:
- https://wiki.php.net/rfc/error_backtraces_v2
- psalm#11975
- phpstan-src#6470| Analyzer | Version | Result | Diagnostics |
|---|---|---|---|
| phan | 6.0.10Phan 6.0.10 php-ast version 1.1.3 PHP version used to run Phan: 8.5.11 | Pass | regressions_error_get_last_trace.php:53: Invalid offset "nope" of $error of array type array{type:int,message:string,file:string,line:int} [PhanTypeInvalidDimOffset] |
| phpstan | 2.3.1PHPStan - PHP Static Analysis Tool 2.3.1 | Pass reported Lv.3+ | regressions_error_get_last_trace.php:53: Offset 'nope' does not exist on array{type: int, message: string, file: string, line: int, trace?: list<array{function: string, line?: int, file?: string, class?: class-string, type?: '->'|'::', args?: list<mixed>, object?: object}>}. [reported-from-level=3]With strict-rulesregressions_error_get_last_trace.php:53: Offset 'nope' does not exist on array{type: int, message: string, file: string, line: int, trace?: list<array{function: string, line?: int, file?: string, class?: class-string, type?: '->'|'::', args?: list<mixed>, object?: object}>}. |
| psalm | 6.20.0Psalm 6.20.0@804f03c0c183d149fcd4b8c7c0c9b3fbf836d34c next: 7.0.0-rc2 |
Pass (pzoom≠) | regressions_error_get_last_trace.php:53: Cannot access value on variable $error using offset value of 'nope', expecting 'file', 'line', 'message', 'trace' or 'type' [InvalidArrayOffset] pzoom (Psalm port)regressions_error_get_last_trace.php:52: Invalid array offset type: 'trace' [InvalidArrayOffset] regressions_error_get_last_trace.php:53: Invalid array offset type: 'nope' [InvalidArrayOffset] |
| mago | 1.57.0mago 1.57.0 | Fail | regressions_error_get_last_trace.php:52: Impossible `isset` check on key `'trace'` accessed on `array{'file': string, 'line': int, 'message': string, 'type': int}`. [impossible-nonnull-entry-check]
regressions_error_get_last_trace.php:52: Redundant null coalesce: left-hand side is always `null`. [redundant-null-coalesce]
regressions_error_get_last_trace.php:53: Undefined array key 'nope' accessed on `array{'file': string, 'line': int, 'message': string, 'type': int}`. [undefined-string-array-index]Expectation diffLine 52: Expected silence (quiet probe), got ["Impossible `isset` check on key `'trace'` accessed on `array{'file': string, 'line': int, 'message': string, 'type': int}`. [impossible-nonnull-entry-check]","Redundant null coalesce: left-hand side is always `null`. [redundant-null-coalesce]"] |
| mir | 0.87.0mir 0.87.0 | Pass | No diagnostics reported. |
| phpantom | 0.11.1phpantom_lsp 0.11.1 | Pass | No diagnostics reported. |
| intelephense | 1.18.5intelephense 1.18.5 | Pass | No diagnostics reported. |
| phpactor | 2026.10.07.0Phpactor 2026.10.07.0 | Pass | No diagnostics reported. |
| phpy | 1.0.19409phpy 1.0.19409 | Pass | No diagnostics reported. |
| qodana | 262.10968.76PhpStorm 262.10968.76 | Fail | regressions_error_get_last_trace.php:52: Value should be one of: "type", "message", "file", "line" [PhpArrayKeyDoesNotMatchArrayShapeInspection] regressions_error_get_last_trace.php:53: Value should be one of: "type", "message", "file", "line" [PhpArrayKeyDoesNotMatchArrayShapeInspection] Expectation diffLine 52: Expected silence (quiet probe), got ["Value should be one of: \"type\", \"message\", \"file\", \"line\" [PhpArrayKeyDoesNotMatchArrayShapeInspection]"] |
| noverify | 0.5.5NoVerify, version 0.5.5: built on: 2025.04.22 14:36:46 OS: r-kuchinskas arm64 Commit: 4774b82f8adc53fbef38f95e97af4b953b4d1529 | Pass | No diagnostics reported. |
| steins | 0.1.8steins 0.1.8 (2026-09-21 revision 76306a9) | Pass | No diagnostics reported. |
| phpstan-strict | 2.3.1PHPStan - PHP Static Analysis Tool 2.3.1 | Pass | regressions_error_get_last_trace.php:53: Offset 'nope' does not exist on array{type: int, message: string, file: string, line: int, trace?: list<array{function: string, line?: int, file?: string, class?: class-string, type?: '->'|'::', args?: list<mixed>, object?: object}>}. |
| psalm-next | 7.0.0-rc2Psalm 7.0.0-rc2@20339e3fe5b8d03bcd8061030eb2a83ad50e5783 | Pass | regressions_error_get_last_trace.php:53: Cannot access value on variable $error using offset value of 'nope', expecting 'file', 'line', 'message', 'trace' or 'type' [InvalidArrayOffset] |
<?php
declare(strict_types=1);
namespace Conformance\Tests\RegressionsErrorGetLastTrace;
/**
* PHP 8.5 adds an optional `trace` key to `error_get_last()`.
*
* `fatal_error_backtraces` is on by default. Fatal errors collected at shutdown
* then carry a `debug_backtrace()`-shaped frame list under `trace`. The RFC
* only populates the key for those fatals, so it is optional; the other four
* keys (`type`, `message`, `file`, `line`) stay required.
*
* A tool whose stub is still the 8.4 shape reports `trace` as an unknown
* offset (`InvalidArrayOffset`, "expecting file, line, message or type"). That
* is the miss this file measures. Access goes through `??` so an honest
* optional-key reading does not also have to warn about a missing offset.
*
* Source: vimeo/psalm#11975, phpstan/phpstan-src#6470. Symfony hit the sealed
* 8.4 shape in symfony/symfony#66145.
*
* References:
* - https://wiki.php.net/rfc/error_backtraces_v2
* - https://github.com/vimeo/psalm/pull/11975
* - https://github.com/phpstan/phpstan-src/pull/6470
*/
function takesInt(int $value): void
{
}
function takesString(string $value): void
{
}
function takesMixed(mixed $value): void
{
}
function inspectLastError(): void
{
$error = error_get_last();
if ($error === null) {
return;
}
takesMixed($error['type']); // V: required 8.4 key
takesMixed($error['message']); // V
takesMixed($error['file']); // V
takesMixed($error['line']); // V
takesMixed($error['trace'] ?? null); // Q: PHP 8.5 optional key — must not be an unknown offset
takesMixed($error['nope']); // E?: unknown key — tools with an unsealed bag stay silent
}
inspectLastError();