Access property of object stored in a constant

php.internals

Ilija Tovilo

3 years ago
Hi everyone Since https://wiki.php.net/rfc/new_in_initializers we can store objects in global constants. However, we may not actually read or write to the properties of those objects without first fetching the constant into a local variable. const a = new stdClass; a->b = 42; // Fatal error: Cannot use temporary expression in write context $a = a; $a->b = 42; // Works fine This issue was reported twice, so it seems like this code is generally expected to work. https://github.com/php/php-src/issues/10497 https://github.com/php/php-src/issues/11781 I have created a patch here to add support for this syntax: https://github.com/php/php-src/pull/11788 Since this is a language change I would like to ask for feedback before merging. As always, if there are concerns I will create a small RFC instead. I will also only merge this for 8.4, as feature freeze for 8.3 has long passed. Ilija

Unnamed Person

3 years ago
On 18-8-2023 17:27, Ilija Tovilo wrote:
> Hi everyone > > Since https://wiki.php.net/rfc/new_in_initializers we can store > objects in global constants. However, we may not actually read or > write to the properties of those objects without first fetching the > constant into a local variable. > > const a = new stdClass; > a->b = 42; // Fatal error: Cannot use temporary expression in write context > $a = a; > $a->b = 42; // Works fine > > This issue was reported twice, so it seems like this code is generally > expected to work. > https://github.com/php/php-src/issues/10497 > https://github.com/php/php-src/issues/11781 > > I have created a patch here to add support for this syntax: > https://github.com/php/php-src/pull/11788 > > Since this is a language change I would like to ask for feedback > before merging. As always, if there are concerns I will create a small > RFC instead. I will also only merge this for 8.4, as feature freeze > for 8.3 has long passed. > > Ilija >
I totally understand that people are trying to do this, but this still very much feels like scope creep. IIRC the new in initializers feature was _intended_ only for enums (which can't take properties). Now suddenly a "constant" would no longer be constant... In which case, what's the point of declaring it as a constant ? Smile, Juliette

Ilija Tovilo

3 years ago
Hi Juliette
> > Since https://wiki.php.net/rfc/new_in_initializers we can store > > objects in global constants. However, we may not actually read or > > write to the properties of those objects without first fetching the > > constant into a local variable. > > > > const a = new stdClass; > > a->b = 42; // Fatal error: Cannot use temporary expression in write context > > $a = a; > > $a->b = 42; // Works fine > > > > This issue was reported twice, so it seems like this code is generally > > expected to work. > > https://github.com/php/php-src/issues/10497 > > https://github.com/php/php-src/issues/11781 > > > > I have created a patch here to add support for this syntax: > > https://github.com/php/php-src/pull/11788 > > I totally understand that people are trying to do this, but this still > very much feels like scope creep. > > IIRC the new in initializers feature was _intended_ only for enums > (which can't take properties). Now suddenly a "constant" would no longer > be constant... In which case, what's the point of declaring it as a > constant ?
This patch doesn't change the mutability of objects in constants, as they already don't offer interior immutability. https://3v4l.org/s7rHE This is analogous to `const` in JavaScript or `readonly` properties in PHP, where we can't change the value of the variable (or const in this case), but we can modify the properties of the object it's pointing to. I believe the main motivation for `new` in constant expressions was to support nested attributes. Enums have their own mechanism for instantiating cases. Since it was decided to expand the support for `new` to global constants, I would expect it to work with other language constructs, unless there's a good reason for it not to. Ilija

Claude Pache

3 years ago
> Le 19 août 2023 à 02:18, Juliette Reinders Folmer <php-internals_nospam@adviesenzo.nl> a écrit : > > > I totally understand that people are trying to do this, but this still very much feels like scope creep. > > IIRC the new in initializers feature was _intended_ only for enums (which can't take properties). Now suddenly a "constant" would no longer be constant... In which case, what's the point of declaring it as a constant ? > > Smile, > Juliette
Hi, It might not be the original intended use. But people are entitled to use features if they find them handy for their purpose. (It was the reason I end up using PHP rather than Java: because it solved problems <https://www.npopov.com/2012/06/29/PHP-solves-problems-Oh-and-you-can-program-with-it-too.html>.) At the time I filed https://github.com/php/php-src/issues/10497, I was merely exploring the potential of the new ability to have an object in a constant. The potential use I had back in my head was the following. Currently, I store some settings in global constants. I was contemplating replacing those by properties of a readonly object stored in a global constant. (A fatal issue I discovered later in my journey is that readonly properties can only be initialised by code inside the class itself.) But in any case, it is good to have regularity in the language. The fact that an object is stored in a constant is completely orthogonal with the fact that the object is mutable, and the proposed patch does not add new capability. (Conversely, the current limitation does not remove any capability.) —Claude

Larry Garfield

3 years ago
On Sat, Aug 19, 2023, at 4:21 AM, Claude Pache wrote:
> At the time I filed https://github.com/php/php-src/issues/10497, I was > merely exploring the potential of the new ability to have an object in > a constant. The potential use I had back in my head was the following. > Currently, I store some settings in global constants. I was > contemplating replacing those by properties of a readonly object stored > in a global constant. (A fatal issue I discovered later in my journey > is that readonly properties can only be initialised by code inside the > class itself.)
As a tangent here, that has a workaround: https://peakd.com/hive-168588/@crell/php-tricks-access-control-bypass Which I make use of in Crell/Serde, which is then used by my own config library to produce exactly what you describe: https://github.com/Crell/Config --Larry Garfield