Category
language · php-src-strict
Problem
foreach ($object as $key => $value) must yield hooked property values by invoking the property get hook, same as get_object_vars() (#5203) and direct reads. Today ObjectPropertyIterator calls ObjectEntry::getProperty() on the raw backing slot; for typed properties with only a get hook (no default), the VM fatals "Typed property must not be accessed before initialization" instead of running the hook.
| API |
Zend PHP 8.4+ |
VM today |
get_object_vars($c) on hooked $x |
["x" => "hooked"] |
"hooked" ✅ |
foreach ($c as $k => $v) |
x=hooked |
fatal on uninitialized typed backing |
php-src reference
Repro
Save as test/repro-maintainer/foreach_property_hooks.php:
<?php
class C {
public string $x {
get { return 'hooked'; }
}
public int $y = 42;
}
$c = new C();
foreach ($c as $k => $v) {
echo "$k=$v\n";
}
./script/docker-exec.sh -- bash -lc 'source script/php-env.sh
php test/repro-maintainer/foreach_property_hooks.php
php bin/vm.php test/repro-maintainer/foreach_property_hooks.php
'
Expected (Zend): x=hooked then y=42
Actual (VM): fatal Typed property C::$x must not be accessed before initialization
Scope (PHP-in-PHP)
| Path |
Work |
lib/VM/ObjectPropertyIterator.php |
Route currentValue() through property read / hook dispatch (mirror get_object_vars path) |
lib/VM.php |
Shared helper for hooked vs plain property reads during iteration |
lib/JIT.php / foreach object lowering |
Match VM hook semantics when JIT foreach-over-object is in scope |
| Tests |
test/compliance/cases/language/foreach_property_hooks.phpt |
No new C in runtime/ — hook semantics belong in PHP VM/JIT lowering.
Done when
Related
Category
language· php-src-strictProblem
foreach ($object as $key => $value)must yield hooked property values by invoking the property get hook, same asget_object_vars()(#5203) and direct reads. TodayObjectPropertyIteratorcallsObjectEntry::getProperty()on the raw backing slot; for typed properties with only a get hook (no default), the VM fatals "Typed property must not be accessed before initialization" instead of running the hook.get_object_vars($c)on hooked$x["x" => "hooked"]"hooked"✅foreach ($c as $k => $v)x=hookedphp-src reference
Zend/zend_property_hooks.c— hooked property read pathZend/zend_execute.c— object foreach uses property read APIZend/zend_foreach.c— object property iterationRepro
Save as
test/repro-maintainer/foreach_property_hooks.php:Expected (Zend):
x=hookedtheny=42Actual (VM): fatal
Typed property C::$x must not be accessed before initializationScope (PHP-in-PHP)
lib/VM/ObjectPropertyIterator.phpcurrentValue()through property read / hook dispatch (mirrorget_object_varspath)lib/VM.phplib/JIT.php/ foreach object loweringtest/compliance/cases/language/foreach_property_hooks.phptNo new C in
runtime/— hook semantics belong in PHP VM/JIT lowering.Done when
x=hookedandy=42on VM (php-src-strict)./script/ci-fast.sh --filter foreach_property_hooksgreenRelated
get_object_vars()get-hook parity