PHP 8.5 accepts closures and first-class callables in constant expressions: constants, parameter and property defaults, and attribute arguments (Enums and Attributes). Built once, such a closure must be static and may not use variables, and arrow functions are refused; the compiler says Closures in constant expressions must be static or Cannot use(...) variables in constant expression. Also new in 8.5, Closure::getCurrent() returns the running closure, so an anonymous function can recurse without the old use (&$walk) trick.
<?php
declare(strict_types=1);
const SLUG = static function (string $s): string {
return trim(preg_replace('/[^a-z0-9]+/', '-', strtolower($s)), '-');
};
function show(string $title, Closure $format = SLUG): void { echo $format($title), "\n"; }
show('PHP 8.5 & You');
$walk = function (array $nodes, int $depth = 0): void {
foreach ($nodes as $name => $children) {
echo str_repeat('-', $depth), $name, ' ';
Closure::getCurrent()($children, $depth + 1); // recurse without a name
}
};
$walk(['Books' => ['Fiction' => ['Crime' => []], 'Science' => []], 'Music' => []]);
echo "\n";php-8-5-you Books -Fiction --Crime -Science Music
The default could equally be a literal static function written inline; before 8.5 it had to be ?Closure $format = null plus a null check. Outside a closure, Closure::getCurrent() throws Error: Current function is not a closure.