Skip to content

ReflectionClass issues with dynamic properties shadowing private parent properties #22441

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions