Accepted 24 to 0, with 1 abstaining, clearing the two-thirds majority it needed. Voting closed on March 13, 2026. The RFC targets PHP 8.6.
Closure optimizations
Makes closures cheaper by inferring static when $this is unused and caching stateless closures, though only the caching part was merged.
Add closure optimizations to PHP 8.6?
This poll has closed.
Summary
This RFC from Ilija Tovilo makes closures faster through two changes, each with small and mostly theoretical backward compatibility breaks. The vote asked whether the speedup was worth those breaks. After the vote passed, only one of the two changes was merged.
Inferring static closures
A closure created inside a class method captures $this, even when it never uses it:
class Foo { public $closure; public function __construct() { $this->closure = fn($a, $b) => $a + $b; } }
Now the object holds the closure and the closure holds the object. PHP's cycle collector has to clean up that reference cycle, and it often doesn't run at all. The first change would mark a closure static automatically when PHP can prove $this isn't used. It skips closures that do anything dynamic, like $$var, Foo::bar(), $f(), call_user_func(), include or eval.
Caching stateless closures
A stateless closure is static, captures no variables and has no static variables. The second change creates it once and reuses it:
function test() { $x = static function () {}; } for ($i = 0; $i < 10_000_000; $i++) { test(); }
Before, this created 10 million closures, and now it creates one. The author measured about an 80% speedup on this benchmark. On the Laravel starter app, the two changes together skipped 2384 of 3637 closure creations, for about a 3% speedup.
What it means for existing code
The RFC lists three small breaks:
ReflectionFunction::getClosureThis()returnsnullfor closures PHP made static.- Two stateless closures created at the same spot in the code are now identical, so
test() === test()istrue. - Objects caught in reference cycles may be freed sooner, so their destructors run sooner.
What was merged
On August 11, 2026, the author added an errata note. Some edge cases broke the static inference change. For example, array_map() can call an instance method through a callable string like 'Foo::instanceCall', and the author says that behavior should be deprecated first. So only the stateless closure caching was merged. If you mark your closures static yourself, you still get the full benefit.