Fix GH-10497: Allow const obj->prop = value - #20903
Conversation
iluuu1994
left a comment
There was a problem hiding this comment.
Thanks @khaledalam! Looks reasonable overall.
Thanks @iluuu1994 for the feedback, all comments addressed. |
|
Cool, thanks @khaledalam! This is a language change and should be discussed on the internals mailing list at least. I think this will impact GH-13800, but that's not a major issue. |
|
Btw, one thing in particular people might object to is: const arrayTest = [1, 2, 3];
arrayTest[] = 4;
var_dump(arrayTest);This becomes valid, but prints: I.e. the assignment has no effect, because it happens on a temporary value. Make sure to mention this in your e-mail to internals. |
|
I've opened an internals thread and sent an email for discussion: https://news-web.php.net/php.internals/129757 |
|
It sounds like @TimWolla objected, so this would need an RFC, or at least the mitigation from https://news-web.php.net/php.internals/129839. |
TimWolla
left a comment
There was a problem hiding this comment.
Yes, my replies on the list were an objection against the PR as-is. Selecting request changes for visibility.
|
Noted, I'll look into it |
d488d10 to
b0a2437
Compare
b0a2437 to
2bd4eb9
Compare
|
Voting closed. The RFC was accepted with 17 (Yes) to 2 (No) votes and 6 abstentions, which is 89.5% acceptance. |
|
@iluuu1994 @TimWolla code review please, RFC voting closed. |
|
Didn't get to it today, tomorrow will have to do, hopefully before the beta 1 cutoff. |
|
The implementation looks nothing like the one I reviewed. What's the reason this was changed? |
|
I'm assuming the changes were made mainly to avoid making OBJ[0]->prop = 42; // disallowed
OBJ->arr[0] = 42; // allowed
OBJ->arr[] = 42; // allowedThere's not much logic as to why the former is disallowed, but the latter is. What we really want to check is whether |
873b39a to
b92bc9f
Compare
|
Should be correct now. Feel free to check. I'll merge tomorrow. |
@iluuu1994 Heads up before you merge, I pushed a fix commit on top of your rewrite. It introduced a regression that I hit while testing the new implementation. Can you please re-review? Compile-time evaluated constants in a write context produce an Invalid opcode fatal: On 8.5 these are all a clean Cannot use temporary expression in write context. Reproduces with and without opcache/JIT. |
78db6ef to
c856726
Compare
|
Thanks for the hint. I believe this was a pre-existing issue but didn't check. I tweaked the implementation a bit. Please check again. |
…nstants Co-authored-by: Ilija Tovilo <ilija.tovilo@me.com>
Use QM_ASSIGN instead of FETCH_CONSTANT, which avoids issues for pseudo-constants like __COMPILER_HALT_OFFSET__ and special handling in the optimizer. Also fix zend_optimizer_pass1() for ops that don't support op1=CONST.
4110c60 to
f593734
Compare
|
@iluuu1994 Thank you, It looks ok for me. I just rebased it to fix conflict. |
Description
RFC: https://wiki.php.net/rfc/const_object_property_write
Discussion thread: https://news-web.php.net/php.internals/129757
Voting thread: https://news-web.php.net/php.internals/132102
Fixes #10497 - Allows direct modification of object properties stored in constants, for both global constants and class constants.
Problem
Previously, this code would fail with a fatal error:
Solution
In zend_delayed_compile_prop(), when the object expression is a constant used in a write context (BP_VAR_W/RW/UNSET/FUNC_ARG), fetch the constant at runtime instead of treating it as a temporary:
Because the constant is fetched at runtime (not compile-time evaluated), the property write targets the real object.
The constant binding itself is never modified.
Scope
Supported:
Still rejected (unchanged):
Backward incompatible change
Enum cases are class constants, so they're affected. Writing to or unsetting a readonly case property, e.g. unset(Enum::Case->value) or Enum::Case->value = x , now raises the standard runtime readonly-property Error instead of the previous compile-time "Cannot use temporary expression in write context" fatal. This matches plain variable access ($x = Enum::Case; unset($x->value);). Enum case properties remain immutable.