Hi,
i've got a little question that involves private properties,
inheritance and Reflection with PHP 5.3 RC1.
Given the following simple classes
class Foo {
private $foo = 'value';
public function getFoo() { return $this->foo; }
}
class Bar extends Foo {}
Obviously, given an instance of Bar, say $bar, $bar->getFoo() returns
'value'.
Now the question: How do I get at this value using reflection, given
an instance of Bar?
$class = new \ReflectionClass('Foo');
$fooProp = $class->getProperty('foo');
$fooProp->setAccessible(true);
$bar = new Bar;
$value = $fooProp->getValue($bar);
var_dump($value); // NULL
var_dump($bar); // array(1) { ["�Foo�foo"]=> string(5) "value" }
How do I get at the value exposed by "var_dump($bar);" through
reflection?
Obviously, I can't upcast like this: "$fooProp->getValue((Foo)$bar)".
I'm asking here because I have the bad feeling that this is might not
(yet?) be possible.
Thanks!
Roman
Given the following simple classes
class Foo {
private $foo = 'value';
public function getFoo() { return $this->foo; }
}
class Bar extends Foo {}Obviously, given an instance of Bar, say $bar, $bar->getFoo() returns
'value'.Now the question: How do I get at this value using reflection, given
an instance of Bar?
class Foo { private $foo = "value"; }
class Bar extends Foo {}
$f = new Foo;
// we have to know the context, as there might be multiple foo properties
$r = new ReflectionProperty("Foo", "foo");
$r->setAccessible(true);
var_dump($r->getValue($f));
works for me.
johannes
Hi,
Given the following simple classes
class Foo {
private $foo = 'value';
public function getFoo() { return $this->foo; }
}
class Bar extends Foo {}Obviously, given an instance of Bar, say $bar, $bar->getFoo() returns
'value'.Now the question: How do I get at this value using reflection, given
an instance of Bar?class Foo { private $foo = "value"; }
class Bar extends Foo {}
$f = new Foo;
// we have to know the context, as there might be multiple foo
properties
$r = new ReflectionProperty("Foo", "foo");
$r->setAccessible(true);
var_dump($r->getValue($f));works for me.
johannes
Thanks for your answer. Yes, this works, but here $f is an instance of
Foo, not Bar. When you make it an instance of Bar you get NULL. I
think this is not correct, is it?
Given that we have a ReflectionProperty of class Foo at hand, from my
understanding it should look at an instance of Bar as a Foo and return
the value. Am I missing something?
Regards
Roman
For what it matters, the same thing in Java returns the expected result:
Class clazz = Foo.class;
Field fooProp = clazz.getDeclaredField("foo");
fooProp.setAccessible(true);
Bar bar = new Bar();
String value = (String)fooProp.get(bar);
System.out.println(value);
So is this a bug or some weird behavior I just don't understand yet?
Roman
Hi,
Given the following simple classes
class Foo {
private $foo = 'value';
public function getFoo() { return $this->foo; }
}
class Bar extends Foo {}Obviously, given an instance of Bar, say $bar, $bar->getFoo()
returns
'value'.Now the question: How do I get at this value using reflection, given
an instance of Bar?class Foo { private $foo = "value"; }
class Bar extends Foo {}
$f = new Foo;
// we have to know the context, as there might be multiple foo
properties
$r = new ReflectionProperty("Foo", "foo");
$r->setAccessible(true);
var_dump($r->getValue($f));works for me.
johannes
Thanks for your answer. Yes, this works, but here $f is an instance
of Foo, not Bar. When you make it an instance of Bar you get NULL. I
think this is not correct, is it?
Given that we have a ReflectionProperty of class Foo at hand, from
my understanding it should look at an instance of Bar as a Foo and
return the value. Am I missing something?Regards
Roman
Hi,
Despite my almost non-existant C-skills I managed to put together a
"patch" (or what I think is a patch) that does not break any tests.
My "patch" is simply to replace the first argument of
zend_update_property/zend_read_property in ext/php_reflection.c like
this:
within the getValue definition:
old: member_p = zend_read_property(Z_OBJCE_P(object), object,
prop_name, strlen(prop_name), 1 TSRMLS_CC);
new: member_p = zend_read_property(ref->ce, object, prop_name,
strlen(prop_name), 1 TSRMLS_CC);
within the setValue definition:
old: zend_update_property(Z_OBJCE_P(object), object, prop_name,
strlen(prop_name), value TSRMLS_CC);
new: zend_update_property(ref->ce, object, prop_name,
strlen(prop_name), value TSRMLS_CC);
So simply replacing Z_OBJCE_P(object) with ref->ce.
I assume "ce" stands for "class entry" and is a zend_class_entry. So
instead of taking the zend_class_entry from the object, we take the
one associated with the reflection property (at least thats what i
assume it does).
I will now try to create a new test for this issue, taking of the
existing tests as a template.
Any comments appreciated.
Roman
For what it matters, the same thing in Java returns the expected
result:Class clazz = Foo.class;
Field fooProp = clazz.getDeclaredField("foo");
fooProp.setAccessible(true);
Bar bar = new Bar();
String value = (String)fooProp.get(bar);
System.out.println(value);So is this a bug or some weird behavior I just don't understand yet?
Roman
Hi,
Given the following simple classes
class Foo {
private $foo = 'value';
public function getFoo() { return $this->foo; }
}
class Bar extends Foo {}Obviously, given an instance of Bar, say $bar, $bar->getFoo()
returns
'value'.Now the question: How do I get at this value using reflection,
given
an instance of Bar?class Foo { private $foo = "value"; }
class Bar extends Foo {}
$f = new Foo;
// we have to know the context, as there might be multiple foo
properties
$r = new ReflectionProperty("Foo", "foo");
$r->setAccessible(true);
var_dump($r->getValue($f));works for me.
johannes
Thanks for your answer. Yes, this works, but here $f is an instance
of Foo, not Bar. When you make it an instance of Bar you get NULL.
I think this is not correct, is it?
Given that we have a ReflectionProperty of class Foo at hand, from
my understanding it should look at an instance of Bar as a Foo and
return the value. Am I missing something?Regards
Roman
My "patch" is simply to replace the first argument of
zend_update_property/zend_read_property in ext/php_reflection.c like
this:
[...]
So simply replacing Z_OBJCE_P(object) with ref->ce.
yes, that was what i was thinking about, too after my first look, but I
have no test environment on this box, will try it later, if nobody steps
in tests&commits :-)
johannes
Hi,
i created 2 patches that are attached to this mail, one to fix the
issue and the other to add tests for it (I added them into
reflectionProperty_setAccessible.phpt).
Roman
Roman Borschel schrieb:
i created 2 patches that are attached to this mail
Your attachments did not make it to the list. No worries, though, I
committed a patch together with updated tests earlier.
--
Sebastian Bergmann Co-Founder and Principal Consultant
http://sebastian-bergmann.de/ http://thePHP.cc/
Thanks for your answer. Yes, this works, but here $f is an instance of
Foo, not Bar. When you make it an instance of Bar you get NULL. I
think this is not correct, is it?
Given that we have a ReflectionProperty of class Foo at hand, from my
understanding it should look at an instance of Bar as a Foo and return
the value. Am I missing something?
Damn, you're right, was too late yesterday evening for me :-)
This really looks like a bug in this feature.
johannes