Show me your privates; just for a second

Discussion of testing theory and practice, including methodologies (such as TDD, BDD, DDD, Agile, XP) and software - anything to do with testing goes here. (Formerly "The Testing Side of Development")

Moderator: General Moderators

User avatar
Ollie Saunders
DevNet Master
Posts: 3179
Joined: Tue May 24, 2005 6:01 pm
Location: UK

Show me your privates; just for a second

Post 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?
User avatar
sweatje
Forum Contributor
Posts: 277
Joined: Wed Jun 29, 2005 10:04 pm
Location: Iowa, USA

Post by sweatje »

Don't. But if you won't listen to me look here.
User avatar
volka
DevNet Evangelist
Posts: 8391
Joined: Tue May 07, 2002 9:48 am
Location: Berlin, ger

Post 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
User avatar
Ollie Saunders
DevNet Master
Posts: 3179
Joined: Tue May 24, 2005 6:01 pm
Location: UK

Post 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);
    }
}
User avatar
volka
DevNet Evangelist
Posts: 8391
Joined: Tue May 07, 2002 9:48 am
Location: Berlin, ger

Post by volka »

What's wrong with reflection? Image
User avatar
Ollie Saunders
DevNet Master
Posts: 3179
Joined: Tue May 24, 2005 6:01 pm
Location: UK

Post by Ollie Saunders »

Tell me
User avatar
volka
DevNet Evangelist
Posts: 8391
Joined: Tue May 07, 2002 9:48 am
Location: Berlin, ger

Post 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.
User avatar
Ollie Saunders
DevNet Master
Posts: 3179
Joined: Tue May 24, 2005 6:01 pm
Location: UK

Post 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++.
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

People seem to commonly add getters which only exist for the tests.
User avatar
Ollie Saunders
DevNet Master
Posts: 3179
Joined: Tue May 24, 2005 6:01 pm
Location: UK

Post 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.
User avatar
volka
DevNet Evangelist
Posts: 8391
Joined: Tue May 07, 2002 9:48 am
Location: Berlin, ger

Post 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";
}
?>
User avatar
sweatje
Forum Contributor
Posts: 277
Joined: Wed Jun 29, 2005 10:04 pm
Location: Iowa, USA

Post 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
User avatar
volka
DevNet Evangelist
Posts: 8391
Joined: Tue May 07, 2002 9:48 am
Location: Berlin, ger

Post 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:
http://cvs.php.net/viewcvs.cgi/php-src/ext/reflection/php_reflection.c?revision=1.164.2.33&view=markup wrote:CVS Tags: php_5_1_3, php_5_1_3RC2, php_5_1_3RC3, php_5_1_4, php_5_1_5, php_5_1_5RC1, php_5_1_6

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.
User avatar
Ollie Saunders
DevNet Master
Posts: 3179
Joined: Tue May 24, 2005 6:01 pm
Location: UK

Post by Ollie Saunders »

What for?
Making a private or protected variable public is not the same as getting its value once.
User avatar
volka
DevNet Evangelist
Posts: 8391
Joined: Tue May 07, 2002 9:48 am
Location: Berlin, ger

Post by volka »

Yes, but the question remains: why? What is its purpose?
Changing the classes behaviour for testing? Not such a good idea.
Post Reply