You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Regression: get-only virtual property write Error is "read-only" — Zend "Must not write to virtual property" (re-#18072, Zend/zend_object_handlers.c) #26006
Language · php-src-strict · PHP 8.4 property hooks · PROFILE=8.4
Problem
Writing (or ++ / +=) a get-only virtual hooked property must throw Error with Zend's virtual-property wording. Under PHP_COMPILER_PROFILE=8.4 the VM still emits the readonly-property message, conflating two distinct Error classes (see closed #18072 / #4687 / #9800).
Repro
Zend 8.4 (php-src)
VM PROFILE=8.4 (2026-07-31)
$c->full = "y" on get-only virtual $full
Must not write to virtual property C::$full
Property C::$full is read-only
$c->n++ on get-only virtual int $n
Must not write to virtual property C::$n
Property C::$n is read-only
Root cause in tree: lib/VM.phpenforceVirtualPropertyHookWrite() uses Property %s::$%s is read-only when $virtual is true; the correct helper raiseVirtualPropertyHookRawAccessError() already formats Must not write to virtual property %s::$%s.
lib/VM.php — enforceVirtualPropertyHookWrite(): for $virtual === true reuse raiseVirtualPropertyHookRawAccessError(..., isRead: false) (or the same sprintf); do not use the readonly message
lib/JIT/PropertyHookDispatchLlvm.php — keep JIT/AOT Error text aligned
Prefer PHP-in-PHP / existing VM Error materialization; no new runtime/*.c
Blocker — acceptance criteria vs php-src PHP-8.4 (Worker Lane C)
Claimed this run; no code change — current VM already matches PHP-8.4 for the filed repro.
What VM does today (PHP_COMPILER_PROFILE=8.4)
arrow assign: Property C::$full is read-only
arrow ++: Property C::$full is read-only
backed: Cannot write property E::$name without set hook
(get => "x" virtual get-only vs backed = "ok" { get => $this->name }.)
What php-src actually says
PHP-8.4 branchZend/zend_object_handlers.c (hooked write, no set, ZEND_ACC_VIRTUAL):
zend_throw_error(NULL, "Property %s::$%s is read-only", ...);
That is the external get-only virtual write path — same string the VM emits.
Must not write to virtual property comes only from zend_throw_no_prop_backing_value_access() — used when a hook tries to touch the backing slot of a virtual property (!zend_should_call_hook + ZEND_ACC_VIRTUAL). That path is already wired here as raiseVirtualPropertyHookRawAccessError().
master tip recently diverged to Cannot write to get-only virtual property %s::$%s for the external path — still notMust not write to virtual property.
Conclusion
Path
PHP-8.4
VM today
Issue expected
External write / ++ on get-only virtual
Property … is read-only
same
Must not write to virtual property ❌
Raw backing access inside hook
Must not write to virtual property
same via helper
(conflated with above)
External write on get-only backed
(without set hook wording)
Cannot write property … without set hook
keep
Implementing the filed Done-when would regress php-src-strict vs PHP-8.4 (and still not match master).
Ask for maintainer retarget: close as not-a-bug for PROFILE=8.4, or open a forward-profile ticket for master’s Cannot write to get-only virtual property wording (not Must not write…).
Unclaiming — Lane C has no other non-stdlib / non-extension implementation-ready issue this run.
claim: Worker Lane C (composer-implementer) — verifying close-out this run
Confirming prior blocker vs php-src PHP-8.4Zend/zend_object_handlers.c (~1174–1178): external get-only virtual write throws Property %s::$%s is read-only. Will add a compliance/repro guard for that Zend string and close as not-a-bug (filed Done-when conflates backing-slot Must not write to virtual property).
Merged #26014 — resolution: not a VM bug under php-src-strict / PROFILE=8.4.
PHP-8.4 external get-only virtual write already emits Property … is read-only (matches Zend/zend_object_handlers.c). Filed Must not write to virtual property conflates the raw backing-slot path. PR adds compliance + repro guards so that wording cannot be “fixed” into a regression.
Activity
PurHur commentedon Jul 31, 2026
claim: Worker Lane C (composer-implementer) — starting this run
PurHur commentedon Jul 31, 2026
Blocker — acceptance criteria vs php-src PHP-8.4 (Worker Lane C)
Claimed this run; no code change — current VM already matches PHP-8.4 for the filed repro.
What VM does today (
PHP_COMPILER_PROFILE=8.4)(
get => "x"virtual get-only vs backed= "ok" { get => $this->name }.)What php-src actually says
PHP-8.4 branch
Zend/zend_object_handlers.c(hooked write, noset,ZEND_ACC_VIRTUAL):That is the external get-only virtual write path — same string the VM emits.
Must not write to virtual propertycomes only fromzend_throw_no_prop_backing_value_access()— used when a hook tries to touch the backing slot of a virtual property (!zend_should_call_hook+ZEND_ACC_VIRTUAL). That path is already wired here asraiseVirtualPropertyHookRawAccessError().master tip recently diverged to
Cannot write to get-only virtual property %s::$%sfor the external path — still notMust not write to virtual property.Conclusion
++on get-only virtualProperty … is read-onlyMust not write to virtual property❌Must not write to virtual propertyCannot write property … without set hookImplementing the filed Done-when would regress php-src-strict vs PHP-8.4 (and still not match master).
Ask for maintainer retarget: close as not-a-bug for PROFILE=8.4, or open a forward-profile ticket for master’s
Cannot write to get-only virtual propertywording (notMust not write…).Unclaiming — Lane C has no other non-
stdlib/ non-extensionimplementation-readyissue this run.PurHur commentedon Jul 31, 2026
claim: Worker Lane C (composer-implementer) — verifying close-out this run
Confirming prior blocker vs php-src PHP-8.4
Zend/zend_object_handlers.c(~1174–1178): external get-only virtual write throwsProperty %s::$%s is read-only. Will add a compliance/repro guard for that Zend string and close as not-a-bug (filed Done-when conflates backing-slotMust not write to virtual property).Language: lock PHP-8.4 get-only virtual write Error as read-only (#26006
PurHur commentedon Jul 31, 2026
Merged #26014 — resolution: not a VM bug under php-src-strict / PROFILE=8.4.
PHP-8.4 external get-only virtual write already emits
Property … is read-only(matchesZend/zend_object_handlers.c). FiledMust not write to virtual propertyconflates the raw backing-slot path. PR adds compliance + repro guards so that wording cannot be “fixed” into a regression.Verification: