rfc:closures_in_const_expr
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
rfc:closures_in_const_expr [2024/10/25 08:57] – timwolla | rfc:closures_in_const_expr [2024/11/13 13:35] (current) – Voting timwolla | ||
---|---|---|---|
Line 2: | Line 2: | ||
* Version: 1.0 | * Version: 1.0 | ||
* Date: 2024-10-24 | * Date: 2024-10-24 | ||
- | * Author: Tim Düsterhus, tim@tideways-gmbh.com | + | * Author: Tim Düsterhus |
- | * Status: | + | * Status: |
* First Published at: https:// | * First Published at: https:// | ||
===== Introduction ===== | ===== Introduction ===== | ||
+ | Several PHP constructs are limited to accept “constant expressions” only. These expressions may only contain a limited number of operations that can roughly be summarized as “immutable values”. Notably attribute parameters are a construct that only accepts constant expressions and Closures are not currently part of the set of allowed operations in constant expressions. | ||
+ | As Closures are effectively just PHP source code (or rather: PHP Opcodes) they are an immutable value (when limiting some of the features) and as such there is no fundamental reason why they should not be allowed within constant expressions. And indeed there are some use cases that would be enabled by allowing Closures to appear in constant expressions. | ||
+ | |||
+ | As an example, it would enable a userland definition of < | ||
+ | |||
+ | <PHP> | ||
+ | <?php | ||
+ | |||
+ | function my_array_filter( | ||
+ | array $array, | ||
+ | Closure $callback = static function ($item) { return !empty($item); | ||
+ | ) { | ||
+ | $result = []; | ||
+ | |||
+ | foreach ($array as $item) { | ||
+ | if ($callback($item)) { | ||
+ | $result[] = $item; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | return $result; | ||
+ | } | ||
+ | |||
+ | var_dump(my_array_filter([ | ||
+ | 0, 1, 2, | ||
+ | '', | ||
+ | ])); | ||
+ | |||
+ | ?> | ||
+ | </ | ||
===== Proposal ===== | ===== Proposal ===== | ||
- | It shall be legal to include Closures in constant expressions. This includes: | + | This RFC proposes that it shall be legal to include Closures in constant expressions. This includes: |
- | * Attributes. | + | * Attribute parameters. |
- | * Default | + | * Default |
* Constants and Class Constants. | * Constants and Class Constants. | ||
==== Constraints ==== | ==== Constraints ==== | ||
- | Closures placed in constant expressions are subject to the following constraints: | + | If Closures |
- | * They must not include variables from the surrounding scope using < | + | * They may not include variables from the surrounding scope using < |
- | * They must be < | + | * They must be < |
- | ==== Use Cases ==== | + | Both of these constraints will be verified at compile time. |
+ | |||
+ | ==== Scoping ==== | ||
+ | |||
+ | As with other constant-expressions, | ||
+ | |||
+ | ==== Closures in sub-expressions ==== | ||
+ | |||
+ | Closures behave like any other operation within a constant expression, thus they may be part of a sub-expression of another operation. While it is not particularly useful to use Closures as an operand to mathematical expressions, | ||
+ | |||
+ | However the following operations are examples of how Closures can usefully be included in sub-expressions. | ||
+ | |||
+ | Defining a list of Closures in a default parameter: | ||
+ | < | ||
+ | <?php | ||
+ | |||
+ | function foo( | ||
+ | string $input, | ||
+ | array $callbacks = [ | ||
+ | static function ($value) { | ||
+ | return \strtoupper($value); | ||
+ | }, | ||
+ | static function ($value) { | ||
+ | return \preg_replace('/ | ||
+ | }, | ||
+ | ] | ||
+ | ) { | ||
+ | foreach ($callbacks as $callback) { | ||
+ | $input = $callback($input); | ||
+ | } | ||
+ | |||
+ | return $input; | ||
+ | } | ||
+ | |||
+ | var_dump(foo(' | ||
+ | </ | ||
+ | |||
+ | Passing a Closure to a < | ||
+ | |||
+ | < | ||
+ | <?php | ||
+ | |||
+ | class MyObject | ||
+ | { | ||
+ | public function __construct(private Closure $callback) {} | ||
+ | } | ||
+ | |||
+ | const Foo = new MyObject(static function () { | ||
+ | return ' | ||
+ | }); | ||
+ | </ | ||
+ | |||
+ | ===== Use Cases ===== | ||
Custom field validation for an attribute-based object validation library: | Custom field validation for an attribute-based object validation library: | ||
<PHP> | <PHP> | ||
- | class Locale | + | final class Locale |
{ | { | ||
# | # | ||
Line 42: | Line 124: | ||
<PHP> | <PHP> | ||
- | class CalculatorTest | + | final class CalculatorTest |
{ | { | ||
# | # | ||
Line 51: | Line 133: | ||
} | } | ||
})] | })] | ||
- | public function testSubtraction(int $minuend, | + | public function testSubtraction(int $minuend, |
{ | { | ||
\assert(Calculator:: | \assert(Calculator:: | ||
Line 58: | Line 140: | ||
</ | </ | ||
+ | Custom formatting for an attribute-based serialization library: | ||
+ | |||
+ | <PHP> | ||
+ | final class LogEntry | ||
+ | { | ||
+ | | ||
+ | |||
+ | # | ||
+ | | ||
+ | })] | ||
+ | | ||
+ | } | ||
+ | </ | ||
===== Backward Incompatible Changes ===== | ===== Backward Incompatible Changes ===== | ||
Line 97: | Line 192: | ||
===== Unaffected PHP Functionality ===== | ===== Unaffected PHP Functionality ===== | ||
- | List existing areas/ | + | Only constant expression are affected by the change and only in a way that Closure objects may appear in places where they previously could not appear in (e.g. class constants). |
- | + | ||
- | This helps avoid any ambiguity, shows that you have thought deeply about the RFC's impact, and helps reduces mail list noise. | + | |
===== Future Scope ===== | ===== Future Scope ===== | ||
Line 105: | Line 198: | ||
* Support non-static Closures. | * Support non-static Closures. | ||
* Support first-class callables. | * Support first-class callables. | ||
+ | * Support variable capturing if/when variables may appear in constant expressions. | ||
===== Proposed Voting Choices ===== | ===== Proposed Voting Choices ===== | ||
- | <doodle title=" | + | <doodle title=" |
* Yes | * Yes | ||
* No | * No |
rfc/closures_in_const_expr.1729846666.txt.gz · Last modified: 2024/10/25 08:57 by timwolla