Page 1 of 2
Show me your privates; just for a second
Posted: Wed Aug 23, 2006 6:58 pm
by Ollie Saunders
Calm down.
I am nighty nine point nine percent sure that the answer to this will be you can't but I'm gonna ask anyway.
I have written a complete class and I want to unit test it. I would like to get access to all the private and protected properties within it for the purpose of the test only, is this possible?
Posted: Wed Aug 23, 2006 7:04 pm
by sweatje
Don't. But if you won't listen to me
look here.
Posted: Wed Aug 23, 2006 7:15 pm
by volka
can be done via reflection.
Code: Select all
<?php
class Foo {
private $bar;
public function __construct() {
$this->bar = 4711;
}
}
$foo = new Foo;
$ref = new ReflectionClass('Foo');
$property = $ref->getProperty('bar');
echo $property->getValue($foo);
?>
see
http://de2.php.net/reflection
Posted: Wed Aug 23, 2006 7:22 pm
by Ollie Saunders
Well I was hoping for something better than reflection but this is actually pretty sweet:
Code: Select all
class OF_UnitTest extends UnitTestCase
{
static function expose($obj, $prop)
{
$reflection = new ReflectionClass($obj);
$prop = $reflection->getProperty($prop);
return $prop->getValue($obj);
}
}
Posted: Wed Aug 23, 2006 7:32 pm
by volka
What's wrong with reflection?

Posted: Wed Aug 23, 2006 7:37 pm
by Ollie Saunders
Tell me
Posted: Wed Aug 23, 2006 7:45 pm
by volka
I don't know, just concluded from
ole wrote:Well I was hoping for something better than reflection
reflection is a mediocre maybe even flawed solution.
Posted: Wed Aug 23, 2006 7:53 pm
by Ollie Saunders
O i c
There was a comment on that link sweatje posted saying that PHP's ReflectionProperty should have a makePublic() method, you could then iterate over an entire object pretty easily. Of course what would be really good is a
friend class akin to C++.
Posted: Wed Aug 23, 2006 7:55 pm
by Chris Corbyn
People seem to commonly add getters which only exist for the tests.
Posted: Wed Aug 23, 2006 7:57 pm
by Ollie Saunders
Yeah, I don't want to do that. This is a library I'm writing here, I don't want a load of getters clogging up the source code when they should really be insulated. Besides its a lot of effort.
Posted: Wed Aug 23, 2006 7:58 pm
by volka
ole wrote:There was a comment on that link sweatje posted saying that PHP's ReflectionProperty should have a makePublic() method,
What for?
Code: Select all
<?php
class Foo {
private $bar1;
private $bar2;
private $barABC;
private $barK;
public function __construct() {
$this->bar1 = rand(1,99);
$this->bar2 = rand(1,99);
$this->barABC = rand(1,99);
$this->barK = rand(1,99);
}
}
$foo = new Foo;
$ref = new ReflectionObject($foo);
$properties = $ref->getProperties();
foreach($properties as $prop) {
echo $prop->getName(), ' : ', $prop->getValue($foo), "<br />\n";
}
?>
Posted: Wed Aug 23, 2006 8:14 pm
by sweatje
volka wrote:ole wrote:There was a comment on that link sweatje posted saying that PHP's ReflectionProperty should have a makePublic() method,
What for?
Code: Select all
<?php
class Foo {
private $bar1;
private $bar2;
private $barABC;
private $barK;
public function __construct() {
$this->bar1 = rand(1,99);
$this->bar2 = rand(1,99);
$this->barABC = rand(1,99);
$this->barK = rand(1,99);
}
}
$foo = new Foo;
$ref = new ReflectionObject($foo);
$properties = $ref->getProperties();
foreach($properties as $prop) {
echo $prop->getName(), ' : ', $prop->getValue($foo), "<br />\n";
}
?>
Code: Select all
bar1 :
Fatal error: Uncaught exception 'ReflectionException' with message 'Cannot access non-public member' in Command line code:20
when run with
Code: Select all
$ php -v
PHP 5.0.3 (cli) (built: Mar 7 2005 22:56:05)
Copyright (c) 1997-2004 The PHP Group
Zend Engine v2.0.3, Copyright (c) 1998-2004 Zend Technologies
also with PHP 5.1.1
Posted: Wed Aug 23, 2006 8:25 pm
by volka
hm, no problems with
PHP 5.1.5 (cli) (built: Aug 15 2006 23:54:56)
and
PHP 5.1.4-pl6-gentoo (cli) (built: Aug 22 2006 01:59:09)
edit:
Code: Select all
/* {{{ proto public mixed ReflectionProperty::getValue([stdclass object])
Returns this property's value */
ZEND_METHOD(reflection_property, getValue)
{
reflection_object *intern;
property_reference *ref;
zval *object;
zval **member= NULL;
METHOD_NOTSTATIC(reflection_property_ptr);
GET_REFLECTION_OBJECT_PTR(ref);
#if MBO_0
if (!(ref->prop->flags & ZEND_ACC_PUBLIC)) {
_DO_THROW("Cannot access non-public member");
/* Returns from this function */
}
#endif
This MBO_0 was obviously not defined when both php versions used by me were compiled.
I don't know what MBO_0 is good for. But it voids the use of reflection in this case
edit #2:
http://www.xy1.org/internals@lists.php.net/msg03498.html wrote:> Hi All,
> what this MBO_0 mean?
cvs convention around these parts. rather than #ifdef 0, the person doing
the #ifdef uses his/her cvs user name appended with "_0". in this case the
guilty party appears to be Marcus.
Posted: Thu Aug 24, 2006 3:29 am
by Ollie Saunders
What for?
Making a private or protected variable public is not the same as getting its value once.
Posted: Thu Aug 24, 2006 1:07 pm
by volka
Yes, but the question remains: why? What is its purpose?
Changing the classes behaviour for testing? Not such a good idea.