Take the State of PHP 2026 Survey →

First Class Callables in constant expressions View as Markdown

Implemented (PHP 8.5)
Authors
Tim Düsterhus (tim@tideways-gmbh.com), Volker Dusch (volker@tideways-gmbh.com)
Date
2025-01-07
Version
1.0
Target
PHP 8.5
Implementation
https://github.com/php/php-src/commit/2042fd34e09c949730570da3c52c20b0b19b7887
Source
wiki.php.net/rfc/fcc_in_const_expr

Vote

Support first class callables in constant expressions as proposed? closed
Yes
29
No
0
29 voters
alcaeus Yes 2025-02-13 10:52
ashnazg Yes 2025-02-12 14:16
beberlei Yes 2025-02-06 15:42
bmajdak Yes 2025-02-07 00:00
brzuchal Yes 2025-02-06 18:10
cpriest Yes 2025-02-14 16:50
crell Yes 2025-02-09 03:55
cschneid Yes 2025-02-06 16:07
derick Yes 2025-02-06 16:02
dharman Yes 2025-02-06 15:44
dragoonis Yes 2025-02-06 19:34
ericmann Yes 2025-02-12 16:41
galvao Yes 2025-02-08 03:00
girgias Yes 2025-02-07 18:24
ilutov Yes 2025-02-06 17:15
josh Yes 2025-02-19 15:10
kguest Yes 2025-02-07 16:04
kinncj Yes 2025-02-06 17:09
lstrojny Yes 2025-02-06 16:47
mbeccati Yes 2025-02-06 19:24
nicolasgrekas Yes 2025-02-12 21:41
nielsdos Yes 2025-02-06 17:54
nikic Yes 2025-02-14 21:06
ramsey Yes 2025-02-07 17:51
sergey Yes 2025-02-11 07:09
theodorejb Yes 2025-02-07 05:18
thorstenr Yes 2025-02-12 15:45
timwolla Yes 2025-02-06 15:43
weierophinney Yes 2025-02-06 15:51

Discussions on the mailing list

[VOTE] First Class Callables in constant expressions
by Volker Dusch · 2 messages

RFC text

Copied from wiki.php.net, last synchronized Oct 13, 2026 11:50 UTC

Introduction

The Support Closures in constant expressions RFC added support for Closures in constant expressions. The RFC left supporting “First Class Callables” (“FCC”), which can be considered syntax sugar for creating a Closure that just forwards any calls to the callable in question.

Given that FCCs effectively act as syntax sugar, the same use cases as with Closures themselves also apply to this RFC. It is intended to round off the “Closures in constant expressions” RFC.

Proposal

This RFC proposes that it shall be legal to use the FCC syntax in constant expressions. The semantics match the existing semantics of FCCs and of constant expressions. Aside from the obvious, this means:

  • If a referenced class does not yet exist, the autoloader is triggered, as with new-expressions in constant expressions.
  • If a relative reference to a free-standing function is used in a namespaced context, the function will first be looked up within the namespace, falling back to the global namespace if it does not exist.

Constraints

All the constraints imposed on FCCs outside of constant expressions naturally also apply to FCCs within constant expressions. Defining a FCC within a constant expression comes with the following additional constraints:

  • Only references to free-standing functions and to static methods (::) are supported.
  • Only the standard function_name(...) or ClassName::methodName(...) references are supported. The function name must not be an expression (constant or otherwise). [ClassName::class, 'methodName'](...), (Constant)(...), or similar are not supported.
  • Referencing methods that implicitly exist due to the existence of a __callStatic() method on the referenced class are not supported.

Scoping

As with other constant-expressions, FCC defined in constant expressions follow the expected scoping rules of the context they are placed in. This means that FCC in property default values may reference private methods of the class where they are defined, similarly to how a FCC defined in the constructor and stored in a property may access those private methods. Likewise are FCC in attribute parameters allowed to access private methods of the surrounding class.

Examples

<?php
 
#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)]
class Attr {
    public function __construct(public Closure $value) {}
}
 
#[Attr(self::myMethod(...))]
#[Attr(strrev(...))]
class C {
    private static function myMethod(string $foo) {
        return "XXX";
    }
}
 
foreach ((new ReflectionClass(C::class))->getAttributes() as $reflectionAttribute) {
    $closure = $reflectionAttribute->newInstance()->value;
    var_dump($closure('abc'));
}
 
// Prints:
//
// string(3) "XXX"
// string(3) "cba"

Backward Incompatible Changes

None. Using first class callables within constant expressions previously resulted in a compile-time error. Closures can appear within constant expressions since the Support Closures in constant expressions RFC.

Nevertheless, as with every RFC that changes what previously was a compile-time error to be valid PHP code, this RFC requires changes to static analyzers and IDEs to correctly understand the semantics of the code and not erroneously report errors.

Proposed PHP Version(s)

Next 8.x (8.5).

RFC Impact

To SAPIs

None.

To Existing Extensions

None.

To Opcache

The current implementation uses a special AST structure to cache the resolved function for consistent behavior of the global function fallback. To correctly cache this AST structure, Opcache changes are required. The PR passes all tests both with and without JIT enabled.

New Constants

None.

php.ini Defaults

None.

Open Issues

None.

Unaffected PHP Functionality

Only constant expression are affected by this change, but Closures could already appear within them.

Future Scope

None.

Proposed Voting Choices

2/3 majority:

Vote: Support first class callables in constant expressions as proposed? — Yes: 29 · No: 0 (closed)

Patches and Tests

https://github.com/php/php-src/pull/17213

Implementation

https://github.com/php/php-src/commit/2042fd34e09c949730570da3c52c20b0b19b7887

References

  1. closures_in_const_expr
  2. https://github.com/php/php-src/pull/17213

Rejected Features

n/a