Skip to content

Partially support first-class callable syntax in constant expressions #9236

Closed as not planned
@pevdh

Description

@pevdh

Description

The first-class callable syntax is currently not allowed in constant expressions:

class X {
    const FN = strlen(...);
}

var_dump((X::FN)('test'));
// PHP Fatal error:  Constant expression contains invalid operations

I propose partially supporting the first-class callable syntax in a constant expression. Specifically, I propose that PHP allows these two cases in a constant context:

class X {
    const A = strlen(...);
    const B = SomeClass::someStaticMethod(...);
}

While (still) disallowing expressions that cannot be known at compile time:

class X {
    const C = $closure(...);
    const D = $obj->method(...);
    const E = ($obj->property)(...);
    // etc. See the first-class callables RFC for a complete list
}

Example

Symfony's Choice assertion allows the user to specify a callback. It would be nice if we could use the first-class callable syntax in attributes, but this is currently not allowed:

use Symfony\Component\Validator\Constraints as Assert;

class User {
     #[Assert\Choice(callback: Role::values(...))] // Using this syntax here causes an error
     public string $role;
}

enum Role: string
{
    case Customer = 'customer';
    case Admin = 'admin';
    
    public static function values() {
        return array_map(fn (Role $a) => $a->name, self::cases());
    }
}

Implementation

I hacked together a working patch that supports the strlen(...) syntax in constant expressions. I haven't gotten around to implementing SomeClass::someStaticFunction(...) yet. There are probably some edge cases that I'm missing - I'm not too familiar with the PHP code base.

I'm also not sure if this feature would require an RFC. I would imagine it would, though.

Please let me know what you think.

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