Category
language
Problem
foreach ($iterable as &$hookedProp) (and foreach ($iterable as $k => &$hookedProp)) must route writes through the property set hook and reads through the get hook, matching Zend zend_property_hooks.c. This compiler’s foreach-by-ref path (lib/VM.php / lib/JIT.php) updates backing slots directly for hooked instance properties.
Distinct from #4599 (Generator foreach by-ref) and #4431 (array foreach parity).
php-src reference
Repro
Save as test/repro-maintainer/parity_property_hook_foreach_byref.php:
<?php
class Acc {
private int $_n = 0;
public int $total {
get => $this->_n;
set => $this->_n = $value * 10;
}
}
$c = new Acc();
foreach ([1, 2, 3] as &$c->total) {
$c->total++;
}
echo $c->total, "\n";
./script/docker-exec.sh -- bash -lc 'source script/php-env.sh
php test/repro-maintainer/parity_property_hook_foreach_byref.php
php bin/vm.php test/repro-maintainer/parity_property_hook_foreach_byref.php
'
| Runtime |
Output |
| Zend PHP 8.4+ |
40 (hooked scaling; exact value follows Zend stepping) |
| VM today |
backing increment without hook scaling (wrong) |
Compliance: test/compliance/cases/language/property_hook_foreach_byref.phpt
Scope (this repo)
| Path |
Work |
lib/VM.php |
FE_FETCH by-ref on hooked property lvalues |
lib/JIT.php / lib/JIT/PropertyHookDispatch.php |
JIT lowering or VM deferral |
| Tests |
VM baseline; JIT when lowering exists |
Done when
Related
Category
languageProblem
foreach ($iterable as &$hookedProp)(andforeach ($iterable as $k => &$hookedProp)) must route writes through the property set hook and reads through the get hook, matching Zendzend_property_hooks.c. This compiler’s foreach-by-ref path (lib/VM.php/lib/JIT.php) updates backing slots directly for hooked instance properties.Distinct from #4599 (Generator foreach by-ref) and #4431 (array foreach parity).
php-src reference
Zend/zend_property_hooks.cZend/zend_execute.c—ZEND_FE_FETCH_R,ZEND_FE_FREEZend/zend_generators.c— foreach on hooked props inside generators (subset)Repro
Save as
test/repro-maintainer/parity_property_hook_foreach_byref.php:40(hooked scaling; exact value follows Zend stepping)Compliance:
test/compliance/cases/language/property_hook_foreach_byref.phptScope (this repo)
lib/VM.phplib/JIT.php/lib/JIT/PropertyHookDispatch.phpDone when
unset($ref)after foreach restores hook semantics (ZendZEND_FE_FREE)./script/ci-fast.sh --filter property_hook_foreach_byrefgreenRelated