Published
Dominik Chrástecký - Blog New in PHP 8.5: Closures as Constant Expressions New in PHP 8.5: Closures as Constant Expressions- 4 min read
New in PHP 8.5: Closures as Constant Expressions

Another exciting PHP 8.5 feature: Closures can now be used as constant expressions, allowing them to appear as default parameters or attribute values.
Ever wanted to set a closure as a default parameter value in PHP, only having to come up with workarounds? In PHP 8.5, that frustration is gone. Closures can now be constant expressions — meaning they work anywhere you’d use a literal value.
I’ve been bitten by this limitation before. Many times. Now, you can use closures in places where you could previously only use values like integers or strings:
- Default parameter values
- Constant values
- Property default values
- Attribute parameter values
- And more
Default values
In the past, I’ve written code like this:
function someFunction(mixed $someValue, ?callable $callback = null): bool
{
$callback ??= fn () => true;
return $callback($someValue);
}
Or this:
final class SomeClass
{
private Closure $someCallable;
public function __construct()
{
$this->someCallable = function (mixed $value): bool {
// todo
return true;
};
}
}
With closures now being constant expressions, both examples can be simplified to:
function someFunction(
mixed $someValue,
callable $callback = static function () { return true; },
): bool {
return $callback($someValue);
}
final class SomeClass
{
private Closure $someCallable = static function (mixed $value): bool {
// todo
return true;
};
}
No more $callback ??=
gymnastics. Using closures directly as default parameter values is something I do fairly often, so being able to tighten the public interface by avoiding nonsense values like null
is a great improvement.
Attributes
This is another great change — you can now define functions directly within attributes. For example:
#[Attribute(Attribute::TARGET_PROPERTY)]
final readonly class TruthyValidator
{
public function __construct(
public Closure $truthyValidator = static function(mixed $value): bool {
return (bool) $value;
}
) {
}
}
Here’s a simple validator attribute that checks whether the value is truthy, with the default implementation just casting it to a boolean and letting PHP handle the conversion. But say you want to consider the string '0'
as truthy:
#[TruthyValidator(truthyValidator: static function(string|int|null $value): bool {
return $value === '0' || $value;
})]
public string|int|null $someProperty = null;
First-Class Callables
This is technically a separate RFC, but it was split for voting reasons rather than technical ones, so I’m covering both in the same article.
In addition to standard closures where you define the function body inline, you can now also use first-class callables as constant expressions. This means all of the above examples also work with them.
<?php
// define a default validator
function defaultValidatorFunction(mixed $value): bool
{
return (bool) $value;
}
// define the validator class
#[Attribute(Attribute::TARGET_PROPERTY)]
final readonly class TruthyValidator
{
public function __construct(
// and assign the default validator using the first-class callable syntax
public Closure $truthyValidator = defaultValidatorFunction(...),
) {
}
}
// define our custom validation function
function truthyValidatorWithoutZeroString(string|int|null $value): bool
{
return $value === '0' || $value;
}
class SomeClassToBeValidated
{
// and use it as a first-class callable
#[TruthyValidator(truthyValidator: truthyValidatorWithoutZeroString(...))]
public string|int|null $someProperty = null;
}
Conclusion
I really like this addition because it — like many other recent improvements — moves PHP toward a cleaner, more consistent language with fewer hacks and a saner syntax.
Where will you use this first? Drop your examples in the comments — I’m curious what creative cases you come up with.
- New in PHP 8.5: Marking Return Values as Important
- New in PHP 8.5: Attributes on Constants
- New in PHP 8.5: Levenshtein Comparison for UTF-8 Strings
- New in PHP 8.5: Final Promoted Properties
- New in PHP 8.5: The Pipe Operator
- New in PHP 8.5: Asymmetric Visibility for Static Properties