PHP 8.5 allows static closures and first-class callables in constant expressions. This means callable values can be used in places that are evaluated as constants, including attribute arguments, property defaults, parameter defaults, and constants.
Static Closure in an Attribute
Example:
<?php
#[Attribute]
class Filter
{
public function __construct(
public Closure $callback
) {}
}
#[Filter(static fn(string $value): bool =>
$value !== ''
)]
function process(string $value): void
{
}
Append this code to instantiate the attribute and call its stored validator:
Example:
$attribute = (new ReflectionFunction('process'))
->getAttributes(Filter::class)[0]
->newInstance();
var_dump(($attribute->callback)('hello'));
var_dump(($attribute->callback)(''));
Output:
bool(true)
bool(false)
Before PHP 8.5, a closure could not be used directly in this kind of constant expression.
Why the Closure Must Be Static
A static closure does not capture $this. That makes it suitable for constant-expression contexts where runtime object binding would be inappropriate.
First-Class Callable Syntax
Example:
<?php
function normalize(string $value): string
{
return strtolower(trim($value));
}
const NORMALIZER = normalize(...);
$normalize = NORMALIZER;
echo $normalize(" HELLO ");
The ... syntax creates a first-class callable reference rather than calling the function immediately.
Use in Default Values
Example:
<?php
function apply(
string $value,
Closure $transform = strtolower(...)
): string {
return $transform($value);
}
This can make APIs more expressive when a callable is genuinely part of configuration.
Where It Can Be Used
| Context | PHP 8.5 |
|---|---|
| Attribute argument | Supported |
| Property default | Supported where the type allows it |
| Parameter default | Supported |
| Constant expression | Supported |
Keep Callables Simple
Constant-expression callables work best for small, declarative behavior such as validators, normalizers, or handlers. Complex application logic is usually easier to test and reuse when it remains in a named function or method.
This feature expands where callable values can be declared; it does not execute the callable during constant evaluation.
Conclusion
PHP 8.5 makes closures and first-class callables more useful as configuration values. Use them when an API naturally accepts behavior as data and a constant-expression context previously forced an indirect workaround.