You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Closure::bind($closure, $newThis, $scope) must return a closure bound to $newThis with $scope, including access to private methods on that scope. The VM builtin mis-dispatches operands: argument #1 is treated as the object (A) instead of the closure, yielding TypeError: Argument #1 ($closure) must be of type Closure, A given.
Repro
Zend 8.2+
VM (2026-07-10)
Closure::bind(function(){ return $this->f(); }, new A(), A::class) where A::f() is private
ext/standard/ closure builtins + lib/VM/ closure bind path — fix operand order / InternalFunction signature for Closure::bind
JIT/AOT: shared lowering for Closure::bind / bindTo if emitted; VM fix is sufficient first gate
Repro
./script/docker-exec.sh -- bash -lc 'php bin/vm.php test/repro/maintainer_gap_closure_bind_private_method.php'# Zend: ok# VM: TypeError Closure::bind(): Argument #1 ($closure) must be of type Closure, A given
Done when
Closure::bind() and Closure::bindTo() accept (closure, object, scope) in php-src order and invoke private methods when scope matches
VM/JIT/AOT agree when JIT path exists
Compliance .phpt guard for bind + private method access
Root cause:slotForStaticClosureBindInlineClosureArg() backward scan hit inline new C() before the closure producer when CFG order is Closure → New_ → ClassConstFetch → StaticCall, wiring newThis into arg #0.
Fix: Skip New_ siblings when scanning backward for the inline closure slot (lib/Compiler.php).
Verification:
php bin/vm.php test/repro/maintainer_gap_closure_bind_private_method.php # ok
vendor/bin/phpunit test/compliance/ClosureVMTest.php test/unit/ClosureCompileTest.php # OK (45 tests)
Activity
PurHur commentedon Jul 10, 2026
claim: PHP Runtime → PHP — starting this run.
Language: fix Closure::bind() inline newThis arg scramble (#17633) (#…
PurHur commentedon Jul 10, 2026
Merged via #17635.
Root cause:
slotForStaticClosureBindInlineClosureArg()backward scan hit inlinenew C()before the closure producer when CFG order isClosure → New_ → ClassConstFetch → StaticCall, wiringnewThisinto arg #0.Fix: Skip
New_siblings when scanning backward for the inline closure slot (lib/Compiler.php).Verification: