Skip to content

Language: isset()/empty() on property-hook virtual properties — get-hook semantics (zend_object_handlers.c parity) #4586

Description

@PurHur

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

Activity

  1. added
    area:vmVirtual machine
    implementation-readySpec complete: repro, php-src ref, done-when — safe for workers to claim
    on Jun 2, 2026
  2. PurHur commented on Jun 2, 2026

    @PurHur
    OwnerAuthor

    claim: worker-lane-c — starting this run

  3. PurHur commented on Jun 2, 2026

    @PurHur
    OwnerAuthor

    Merged via #4591

    Verification

    • `php bin/vm.php test/repro-maintainer/property_hook_isset.php` → `true` / `false`
    • `./vendor/bin/phpunit --filter property_hook_isset` → OK (1 test)
    • Compliance: `test/compliance/cases/language/property_hook_isset.phpt`

    VM invokes get hooks for `isset`/`empty` on hooked properties; JIT lowering added in `PropertyHookDispatch::tryEmitPropertyIsSet`. MCJIT execute for property-hook scripts remains skipped in `JITTest` (existing #4025 gate).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:compilerCompiler / CFG / JITarea:vmVirtual machineimplementation-readySpec complete: repro, php-src ref, done-when — safe for workers to claimphase-2:languagePhase 2 – language features

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions