Category
Language · php-src-strict / @ silence + error_get_last
Problem
@$undef inside a compiled closure (or the same pattern in a user function) is silent on both Zend and VM (good), but Zend still records the warning in error_get_last() while VM/JIT leave error_get_last() null.
File-scope @$undef already updates error_get_last() (control). Builtin @preg_match('/(/', …) inside a closure already records the message (control; #13662). This is the language undefined-variable + ZEND_BEGIN_SILENCE path in a nested frame.
Probed 2026-08-18 @ 87cba84dc2 — Zend 8.2.32 vs php bin/vm.php / php bin/jit.php.
| Repro |
Zend 8.2.32 |
VM/JIT |
closure: error_clear_last(); @$undef; error_get_last() |
type=2 Undefined variable $undef |
type=none (null) |
file-scope @$undef then error_get_last() |
type=2 same message |
type=2 ✓ |
closure: unsileced $undef then error_get_last() |
records; line = inner |
records; line = call site (see sibling nested-frame line issue) |
closure: @preg_match('/(/','a') |
records preg Compilation failed |
records ✓ |
php-src reference
PHP implementation target
lib/VM.php — silenced undefined-variable in a callee frame must still snapshot into the error_get_last buffer (same as file-scope @)
lib/VM/ErrorReporter.php (or existing silence helpers) — @ suppresses display, not last-error storage
- No new
runtime/*.c
Repro
./script/docker-exec.sh -- bash -lc 'php bin/vm.php test/repro/maintainer_gap_error_get_last_at_undef_closure.php'
./script/docker-exec.sh -- bash -lc 'php bin/jit.php test/repro/maintainer_gap_error_get_last_at_undef_closure.php'
./script/docker-exec.sh -- bash -lc 'php test/repro/maintainer_gap_error_get_last_at_undef_closure.php' # Zend baseline
<?php
error_reporting(E_ALL);
error_clear_last();
$fn = function () {
@ $undef;
$e = error_get_last();
echo 'type=', $e['type'] ?? 'none', "\n";
echo 'msg=', $e['message'] ?? 'none', "\n";
};
$fn();
Done when
Category
Language· php-src-strict /@silence +error_get_lastProblem
@$undefinside a compiled closure (or the same pattern in a user function) is silent on both Zend and VM (good), but Zend still records the warning inerror_get_last()while VM/JIT leaveerror_get_last()null.File-scope
@$undefalready updateserror_get_last()(control). Builtin@preg_match('/(/', …)inside a closure already records the message (control; #13662). This is the language undefined-variable +ZEND_BEGIN_SILENCEpath in a nested frame.Probed 2026-08-18 @
87cba84dc2— Zend 8.2.32 vsphp bin/vm.php/php bin/jit.php.error_clear_last(); @$undef; error_get_last()type=2Undefined variable $undeftype=none(null)@$undefthenerror_get_last()type=2same messagetype=2✓$undefthenerror_get_last()@preg_match('/(/','a')php-src reference
Zend/zend_execute.c—ZEND_BEGIN_SILENCE/EG(error_reporting)for@; silenced errors still populateEG(last_error)Zend/zend_builtin_functions.c—PHP_FUNCTION(error_get_last)readsEG(last_error)Zend/zend_errors.c—zend_errorstores last error even when reporting is 0PHP implementation target
lib/VM.php— silenced undefined-variable in a callee frame must still snapshot into theerror_get_lastbuffer (same as file-scope@)lib/VM/ErrorReporter.php(or existing silence helpers) —@suppresses display, not last-error storageruntime/*.cRepro
Done when
@$undefinside a closure/function updateserror_get_last()to E_WARNINGUndefined variable $undef(Zend); no user-visible Warning@$undefand@preg_matchmalformed inside a closure unchanged (already green).phptundertest/compliance/cases/language/