rfc:fetch_property_in_const_expressions

This is an old revision of the document!


PHP RFC: Fetch properties in const expressions

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 and value 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.

Add support for fetching properties in constant expressions?
Real name Yes No
Final result: 0 0
This poll has been closed.
rfc/fetch_property_in_const_expressions.1654173229.txt.gz · Last modified: 2022/06/02 12:33 by ilutov