This is an old revision of the document!
PHP RFC: Fetch properties in const expressions
- Date: 2022-05-27
- Author: Ilija Tovilo ilutov@php.net
- Status: Under discussion
- Proposed Version: PHP 8.2
- Implementation: https://github.com/php/php-src/pull/8625
Introduction
This RFC proposes to allow use of ->
/?->
to fetch properties in constant expressions. The primary motivation for this change is to allow fetching the name
and value
properties of enums in places where enum objects aren't allowed, like array keys (see https://github.com/php/php-src/issues/8344). There is currently no way to express this without repeating the value of the enum case.
enum A: string { case B = 'B'; // This is currently not permitted const C = [self::B->value => self::B]; }
Proposal
This RFC proposes to allow the use of ->
to fetch properties inside all constant expressions. As ->
may only be used on objects there are two scenarios where ->
can be used:
- Enums (for the
name
andvalue
properties) new
(for any declared property or magic__get
)
Here are a few examples of code that will become valid if this RFC is accepted:
// Where E::B is a unit enum const A = E::B->name; // Where E::C is a backed enum function a() { static $b = E::C->value; } // Where B is a class with a property $c #[A((new B)->c)] class D {} // Where C::$d is an object with a property $e function a( $b = (new C)->d->e ) {} // The rhs of -> allows other constant expressions const A = 'foo'; const B = (new C)->{A};
As mentioned, the primary motivation for this feature are enums. However, the implementation for supporting new
is identical and I don't believe arbitrarily restricting how ->
can be used in this context makes sense.
For the sake of completeness, this RFC also adds support for the nullsafe operator ?->
.
Semantics
The semantics of ->
in constant expressions are identical to outside of constant expressions, including access on non-object warnings, undefined property warnings, etc.
class A {} // Warning: Undefined property: A::$c const B = (new A)->c; // NULL // Note that this will change to an error in PHP 9 https://wiki.php.net/rfc/undefined_property_error_promotion // Warning: Attempt to read property "e" on null const D = (null)->e; // NULL // Warning: Attempt to read property "" on null // Fatal error: Uncaught Error: Object of class A could not be converted to string const F = (null)->{new A};
Likewise, the semantics of the nullsafe operator ?->
are identical to outside of constant expressions. If the left hand side of the operator is null
, the expression returns null
, the right hand side is not evaluated and the entire chain is short-circuited.
const A = (null)?->b; // NULL const C = (null)?->d->e; // NULL const F = (null)?->{new NotInstanciated}; // NULL
Backward Incompatible Changes
There are no backwards-incompatible changes in this RFC.
Alternative approaches
Alternatively, arrays could be extended to allow enums or all objects as keys. This is the approach of the object keys in arrays RFC. While this RFC still might be worthwhile it comes with significant API changes in the engine and it does break the assumption in userland code that array keys are of type int|string
.
Terminology
Note that the term “constant expression” in this RFC refers to any expression that isn't directly compiled to OpCodes but instead stored as a constant AST which is evaluated at run-time. Since allowing new
in these expressions the result is no longer guaranteed to be pure or constant.
Vote
Voting opened on xxx and closes on xxx.