PHP Closures and Callables in Constant Expressions

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.



Found This Page Useful? Share It!
Get the Latest Tutorials and Updates
Join us on Telegram