Skip to content

ReflectionClass issues with dynamic properties shadowing private parent properties #22441

Closed

Description

@DanielEScherzer

Description

The following code:

<?php

class Base {
    private mixed $shadow;
}

#[AllowDynamicProperties]
class Child extends Base {}

$o = new Child();
$o->shadow = true;
$o->noShadow = true;
var_dump($o);
echo "\n";

$r = new ReflectionObject($o);

echo "hasProperty():\n";
var_dump($r->hasProperty('shadow'));
var_dump($r->hasProperty('noShadow'));
echo "\n";

echo "getProperty():\n";
try {
    var_dump($r->getProperty('shadow'));
} catch (\Throwable $e) {
    echo $e->getMessage(). "\n";
}
echo "\n";
var_dump($r->getProperty('noShadow'));

echo "\n";
echo "getProperties():\n";
var_dump($r->getProperties());

Resulted in this output:

object(Child)#1 (2) {
  ["shadow":"Base":private]=>
  uninitialized(mixed)
  ["shadow"]=>
  bool(true)
  ["noShadow"]=>
  bool(true)
}

hasProperty():
bool(false)
bool(true)

getProperty():
Property Child::$shadow does not exist

object(ReflectionProperty)#4 (2) {
  ["name"]=>
  string(8) "noShadow"
  ["class"]=>
  string(5) "Child"
}

getProperties():
array(2) {
  [0]=>
  object(ReflectionProperty)#4 (2) {
    ["name"]=>
    string(6) "shadow"
    ["class"]=>
    string(5) "Child"
  }
  [1]=>
  object(ReflectionProperty)#5 (2) {
    ["name"]=>
    string(8) "noShadow"
    ["class"]=>
    string(5) "Child"
  }
}

But I expected this output instead:

object(Child)#1 (2) {
  ["shadow":"Base":private]=>
  uninitialized(mixed)
  ["shadow"]=>
  bool(true)
  ["noShadow"]=>
  bool(true)
}

hasProperty():
bool(true)
bool(true)

getProperty():
object(ReflectionProperty)#4 (2) {
  ["name"]=>
  string(8) "shadow"
  ["class"]=>
  string(5) "Child"
}

object(ReflectionProperty)#5 (2) {
  ["name"]=>
  string(8) "noShadow"
  ["class"]=>
  string(5) "Child"
}

getProperties():
array(2) {
  [0]=>
  object(ReflectionProperty)#4 (2) {
    ["name"]=>
    string(6) "shadow"
    ["class"]=>
    string(5) "Child"
  }
  [1]=>
  object(ReflectionProperty)#5 (2) {
    ["name"]=>
    string(8) "noShadow"
    ["class"]=>
    string(5) "Child"
  }
}

ReflectionClass::hasProperties() and ::getProperty() only check dynamic properties after checking for a matching property of the same name that could be a private parent property

PHP Version

8.4+

Operating System

No response

Activity

  1. DanielEScherzer commented on Jun 24, 2026

    @DanielEScherzer
    MemberAuthor

    https://3v4l.org/Ypsq5#v8.5.8
    Filing this for the record, I should be able to get to it within a few days, though if a new contributor wants to try tackling this it should be pretty easy and I'm happy to mentor/review

  2. self-assigned this
    on Jun 25, 2026
  3. added a commit that references this issue on Jun 25, 2026
    86d78cc
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions