Skip to content

Language: empty() on uninitialized typed properties — php-src returns true without throw (regression vs #4912, zend_object_handlers.c) #6787

Closed

Description

@PurHur

Category

language | php-src-strict

Problem

Zend treats empty($obj->uninitTyped) and empty(Class::$uninitStatic) as true without throwing; isset() stays false. This compiler throws Error: Typed property … must not be accessed before initialization for empty() on both instance and static uninitialized typed properties.

Closed #4912 + compliance empty_uninitialized_typed_property.phpt codified the throw behavior; php-src parity requires reverting to Zend semantics and updating the compliance expectation.

php-src reference

Repro (failure today)

<?php
class T {
    public int $i;
    public static int $s;
}
$t = new T();
echo 'isset i=', var_export(isset($t->i), true), ' empty i=', var_export(empty($t->i), true), PHP_EOL;
echo 'isset s=', var_export(isset(T::$s), true), ' empty s=', var_export(empty(T::$s), true), PHP_EOL;
./script/docker-exec.sh -- bash -lc 'source script/php-env.sh
php repro.php
php bin/vm.php repro.php 2>&1
'
Line Zend PHP 8.x VM today
instance isset / empty false / true false / fatal Error
static isset / empty false / true fatal Error on empty

Existing maintainer repro: test/repro/maintainer_empty_uninit_php_src.php (if present).

Scope (this repo)

Path Work
VM lib/VM.php, EmptyObjectPropertyHelper — empty() must not invoke full read on uninitialized typed slots (instance + static)
JIT lib/JIT/EmptyObjectPropertyHelper.php — same for TYPE_EMPTY_OBJECT_PROPERTY / static variants
AOT Mirror JIT guards when lowered
Compliance Update test/compliance/cases/language/empty_uninitialized_typed_property.phpt EXPECT to php-src output

PHP-in-PHP: no runtime/*.c.

Done when

  • Repro prints four lines matching Zend (isset false, empty true) for instance and static
  • Direct read $t->i / T::$s still throws Error (unchanged)
  • isset() behavior unchanged (already false)
  • ./script/ci-fast.sh --filter empty_uninitialized green on VM + JIT/AOT

Verification

./script/docker-exec.sh -- bash -lc 'source script/php-env.sh && vendor/bin/phpunit --filter empty_uninitialized'

Strictness

php-src-strict — default CI/compliance must match Zend, not #4912 throw semantics.

Related

Activity

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

    @PurHur
    OwnerAuthor

    claim: worker-lane-b — starting this run

  3. PurHur commented on Jun 6, 2026

    @PurHur
    OwnerAuthor

    Merged via #6873

    Fix: empty() on uninitialized typed instance/static properties returns true without throwing (php-src parity; reverts #4912 throw semantics).

    Verification:
    ```bash
    ./script/docker-exec.sh -- bash -lc 'source script/php-env.sh
    php test/repro/6787_empty_uninit_typed.php
    php bin/vm.php test/repro/6787_empty_uninit_typed.php
    vendor/bin/phpunit --filter empty_uninitialized
    '
    ```
    VM repro: isset i=false empty i=true / isset s=false empty s=true — PHPUnit OK (2 tests, VM + JIT).

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 machineenhancementNew feature or requestimplementation-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