Skip to content

short closures in constant expressions #21033

@damek24

Description

@damek24

Description

The following code:

declare(strict_types=1);

#[Attribute(Attribute::TARGET_PROPERTY)]
class TestAttribute
{
    public function __construct(
        public $callback
    ) {}
}


final class Clock
{
    public function format(string $format): string
    {
        return $format;
    }
}

final class Example
{
    // This version FAILS (Fatal error: Constant expression contains invalid operations)
    #[TestAttribute(static fn (Clock $clock) => $clock->format('Y-m-d H:i:s'))]

    // This version PASSES
    //#[TestAttribute(static function (Clock $clock) {
    //    return $clock->format('Y-m-d H:i:s');
    //})]
    public ?Clock $created_at = null;
}

$ref = new ReflectionProperty(Example::class, 'created_at');
$attr = $ref->getAttributes(TestAttribute::class)[0]->newInstance();

var_dump($attr->callback instanceof Closure);

Resulted in this output:
Fatal error: Constant expression contains invalid operations

But I expected this output instead:
bool(true)

https://3v4l.org/Hdf3V#v8.5.2

Both constructs produce a Closure and are runtime-equivalent. The difference appears to be a parser or constant-expression validation inconsistency. The RFC (https://wiki.php.net/rfc/closures_in_const_expr) uses normal anonymous functions as an example. Short closures aren't mention neither as known limitations / disallowed behavior nor future scope. If this is desired behavior and static short closures are not supported here - please this information somewhere to the docs

PHP Version

PHP 8.5.1 (cli) (built: Dec 18 2025 23:39:41) (NTS)
Copyright (c) The PHP Group
Built by Debian
Zend Engine v4.5.1, Copyright (c) Zend Technologies
    with Zend OPcache v8.5.1, Copyright (c), by Zend Technologies

Operating System

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions