Skip to content

Language: final plain properties isFinal=0 + child override accepted under PROFILE=8.4 (re-#27315, Zend/zend_inheritance.c) #27818

Closed

Description

@PurHur

Category

Language · php-src-strict · PHP 8.4 final properties

Problem

Under PHP_COMPILER_PROFILE=8.4, plain final public properties still report ReflectionProperty::isFinal() === false, and a child class may redeclare the same property. Zend/php-src 8.4+ keeps post-construct writes allowed (inheritance-only final) but isFinal() is true and child redeclaration is a compile fatal. Previously closed as fixed in #27315 / PR #27336 — regressed on master (verified 2026-08-05).

Repro Zend 8.4+ VM/JIT PROFILE=8.4 (2026-08-05)
final public string $x; write after construct write OK write OK (correct)
ReflectionProperty::isFinal() true / 1 false / 0
class B extends A { public string $x = ... } compile fatal accepted (override_ok)

php-src reference

PHP implementation target

  • lib/ property / class compile + inheritance checks — set final flag on plain properties; reject child redeclaration
  • ext/reflection / ReflectionProperty path — surface isFinal() from the flag (not a C-only shortcut)
  • Reuse committed repro test/repro/maintainer_gap_final_plain_property_84.php (+ add override fatal case)

Repro

./script/docker-exec.sh -- bash -lc 'PHP_COMPILER_PROFILE=8.4 php bin/vm.php test/repro/maintainer_gap_final_plain_property_84.php'
# expect: wrote / isFinal=1
# actual: wrote / isFinal=0

./script/docker-exec.sh -- bash -lc 'PHP_COMPILER_PROFILE=8.4 php bin/vm.php -r "
class A { final public string \$x = \"a\"; }
class B extends A { public string \$x = \"c\"; }
echo \"bad\n\";
"'
# expect: Fatal error (cannot override final property)
# actual: prints bad

Done when

  • PROFILE=8.4 VM/JIT/AOT: isFinal=1 on committed repro; post-construct write still succeeds (Zend inheritance-only semantics)
  • Child redeclaration of a final plain property is a compile fatal matching Zend
  • Compliance/unit guard under test/compliance/ or test/unit/ for isFinal + override
  • php-src-strict; no php-compiler-strict shortcut

Activity

  1. added
    bugSomething isn't working
    implementation-readySpec complete: repro, php-src ref, done-when — safe for workers to claim
    on Aug 5, 2026
  2. PurHur commented on Aug 5, 2026

    @PurHur
    OwnerAuthor

    claim: worker-lane-C — starting this run

    Pillar snapshot (pre-claim):

    Repro target: PROFILE=8.4 final plain property isFinal + child override fatal (re-#27315).

  3. PurHur commented on Aug 5, 2026

    @PurHur
    OwnerAuthor

    claim: worker-lane-C — continuing this run (prior claim had no PR/branch; taking implementation)

    Pillar snapshot:

  4. PurHur commented on Aug 5, 2026

    @PurHur
    OwnerAuthor

    merged: #27861 (435f54089c)

    Verification (Docker ./script/docker-exec.sh):

    • Issue-body plain repro PROFILE=8.4 VM/AOT: wrote / isFinal=1 (already green on tip; locked)
    • Trait-imported final (AOT hole closed): VM/AOT isFinal=1; child override AOT build exit 255 Cannot override final property A::$x
    • vendor/bin/phpunit --filter FinalPropertyOverrideCheckTest OK (21)
    • vendor/bin/phpunit --filter final_plain_property_trait_isfinal_84 OK

    Root cause: inheritTraitInstanceProperties copied readonly but not ZEND_ACC_FINAL into Object_::finalPropertyNames; FinalPropertyOverrideCheck ignored TraitUse.

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 / JITbugSomething isn't workingimplementation-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