Category
language
Problem
Property hooks (get / set) lower and dispatch on normal reads/writes (#3145, #3723), but isset($obj->prop) and empty($obj->prop) on hook-only virtual properties do not invoke the get hook. VM uses objectPropertyIsSet() which only inspects raw storage + __isset magic — it never calls fetchPropertyWithHooks().
Zend PHP 8.4+ treats hooked properties like real properties for isset/empty (get hook invoked; result checked for null/undefined).
php-src reference
Repro
<?php
class Box {
public string $label {
get => strtoupper($this->label);
set (string $v) { $this->label = $v; }
}
public function __construct() { $this->label = 'hi'; }
}
$o = new Box();
var_export(isset($o->label));
echo "\n";
var_export(empty($o->label));
echo "\n";
./script/docker-exec.sh -- bash -lc 'source script/php-env.sh && php bin/vm.php repro.php'
php repro.php
| Runtime |
Expected |
| Zend PHP 8.4+ |
true / false (label is 'HI', non-empty) |
| VM today |
likely false / true (raw backing unset from isset's POV) |
Minimal get-only hook:
<?php
class R {
public int $n { get => 42; }
}
$r = new R();
var_export(isset($r->n), empty($r->n));
Scope (this repo)
| Layer |
Path |
| VM |
lib/VM.php — objectPropertyIsSet(), TYPE_ISSET / TYPE_EMPTY on object props |
| Compiler |
no syntax change |
| JIT |
lib/JIT/PropertyHookDispatch.php — isset/empty must not bypass hooks |
| Tests |
test/compliance/cases/language/property_hook_isset.phpt |
Do not permanently stub with internal_*; invoke get hook like normal fetch, then apply isset/empty rules to returned value.
Done when
Related
Category
languageProblem
Property hooks (
get/set) lower and dispatch on normal reads/writes (#3145, #3723), butisset($obj->prop)andempty($obj->prop)on hook-only virtual properties do not invoke the get hook. VM usesobjectPropertyIsSet()which only inspects raw storage +__issetmagic — it never callsfetchPropertyWithHooks().Zend PHP 8.4+ treats hooked properties like real properties for
isset/empty(get hook invoked; result checked for null/undefined).php-src reference
Zend/zend_object_handlers.c—zend_std_has_property, hooked property isset pathZend/zend_compile.c— property hook metadataisset/emptybehaviorRepro
./script/docker-exec.sh -- bash -lc 'source script/php-env.sh && php bin/vm.php repro.php' php repro.phptrue/false(label is'HI', non-empty)false/true(raw backing unset from isset's POV)Minimal get-only hook:
Scope (this repo)
lib/VM.php—objectPropertyIsSet(),TYPE_ISSET/TYPE_EMPTYon object propslib/JIT/PropertyHookDispatch.php— isset/empty must not bypass hookstest/compliance/cases/language/property_hook_isset.phptDo not permanently stub with
internal_*; invoke get hook like normal fetch, then apply isset/empty rules to returned value.Done when
bin/jit.php repro.php)./script/ci-fast.sh --filter property_hook_issetgreen__issetmagic (Language: isset($obj->prop) on undefined property — return false (Zend zend_operators.c parity) #3603)Related