I am creating a class that uses ReflectionProperty and am getting strange results.
Essentially, calling $reflectionProperty->getType()->getName()
is returning the value of some entirely unrelated array. It does this under seemingly random conditions.
See below:
// this will be used as a type hinted property.
class DummyClass {
public function __construct($arr) {}
}
// a class that sets its property values reflectively
class BaseClass {
/** @var ReflectionProperty[] */
private static $publicProps = [];
/**
* Gets public ReflectionProperties of the concrete class, and caches them
* so we do not need to perform reflection again for this concrete class.
*
* @return ReflectionProperty[]
* @throws ReflectionException
*/
private function getPublicProps(){
if (!static::$publicProps) {
$concreteClass = get_class($this);
static::$publicProps = (new ReflectionClass($concreteClass))
->getProperties(ReflectionProperty::IS_PUBLIC);
}
return static::$publicProps;
}
/**
* For each public property in this class set value to the corresponding value from $propArr.
*
* @param $propArr
* @throws ReflectionException
*/
public function __construct($propArr) {
$concreteClass = get_class($this);
echo "Creating new instance of $concreteClass<br>";
foreach ($this->getPublicProps() as $prop) {
// get which property to set, its class, and value to pass to constructor
$propName = $prop->getName();
$propClass = $prop->getType()->getName();
$propValue = $propArr[$propName];
$propValueStr = var_export($propValue, true);
// print out what we are about to do, and assert $propClass is correct.
echo "---Setting: ->$propName = new $propClass($propValueStr)<br>";
assert($propClass === "DummyClass", "$propClass !== DummyClass");
// create the instance and assign it
$refClass = new ReflectionClass($propClass);
$this->$propName = $refClass->newInstanceArgs([$propValue]);
}
}
}
// a concrete implementation of the above class, with only 1 type hinted property.
class ConcreteClass extends BaseClass {
public DummyClass $prop1;
}
// should create an instance of ConcreteClass
// with ->prop1 = new DummyClass(["foo"=>"abc123"])
$testArr1 = [
"prop1" => ["foo" => "abc123"]
];
// should create an instance of ConcreteClass
// with ->prop1 = new DummyClass(["boo"=>"abc123def456"])
$testArr2 = [
"prop1" => ["boo" => "abc123def456"]
];
$tc1 = new ConcreteClass($testArr1);
echo "Created TestClass1...<br><br>";
$tc2 = new ConcreteClass($testArr2);
echo "Created TestClass2...<br><br>";
die;
The results:
Creating new instance of ConcreteClass
Setting: ->prop1 = new DummyClass(array ( 'foo' => 'abc123', ))
Created TestClass1...
Creating new instance of ConcreteClass
Setting: ->prop1 = new abc123def456(array ( 'boo' => 'abc123def456', ))
Error: assert(): abc123def456 !== DummyClass failed
Notice that the value of $propClass
is abc123def456
-- how did that happen?
More Weirdness
- Change the value of "abc123def456" to "12345678" and it will work.
- Change the value of "abc123def456" to "123456789" and it will not work.
- Omit the var_export(), and it will work. (Though, it may still break in other cases).
My gut tells me this is a PHP bug, but I might be doing something wrong, and/or this may be documented somewhere. I would like some clarification, because as of right now my only reliable solution is to not cache the reflected $publicProps. This results in an unnecessary call to ReflectionClass->getProperties()
every single time I create a new ConcreteClass
, which I'd like to avoid.
Aucun commentaire:
Enregistrer un commentaire