jLuengas
jLuengas

Reputation: 71

How to get a a property value by reference using reflection in PHP?

Suppose you have a class declared like this:

class DummyObject{
    public $attr;
    public function __construct(){
        $this->attr=array('val_1','val_2','val_3');
    }
}

Doing this:

$obj=(new DummyObject1());
$attr=&$obj->attr;

You'll get a reference to $attr so any modifications made in the array will be made also in DummyObject $obj instance.

And now, finally the question. Using reflection, ¿how can I get a reference to the array stored in $attr and not a copy?. I've tried this without success:

$obj=(new DummyObject());
$reflector = new ReflectionObject($obj);
$reflectorProperty = $reflector->getProperty('attr');
$propertyValue=$reflectorProperty->getValue($ref);

In fact,$attr is a copy of original array.

Thanks in advance!

Upvotes: 3

Views: 2122

Answers (3)

Ocramius
Ocramius

Reputation: 25431

Since PHP 5.4 you can do this without reflection:

class Kitchen
{
    private $yummy = 'cake';
}

$reader = function & ($object, $property) {
    $value = & Closure::bind(function & () use ($property) {
        return $this->$property;
    }, $object, $object)->__invoke();

    return $value;
};

$kitchen = new Kitchen();
$cake    = & $reader($kitchen, 'yummy');
$cake    = 'sorry, I ate it!';

var_dump($kitchen);

This is thanks to the ability of PHP 5.4 to switch the scope of a closure at runtime.

You can find a running example at http://3v4l.org/sZMt1

I actually explained the technique and eventual use cases in detail at http://ocramius.github.io/blog/accessing-private-php-class-members-without-reflection/

Upvotes: 9

antonpinchuk
antonpinchuk

Reputation: 453

You can get it from original $obj that you can pass to callback via "use" statement

$propertyValue = $obj->{$reflectorProperty->getName()};

Or if you use public getters/setters for private members you can

$propertyName = $reflectorProperty->getName();
$methodName = 'get' . ucfirst($propertyName);
if (method_exists($obj, $methodName)) {
    $propertyValue = call_user_func([ $object, $methodName ]);
} elseif (isset($obj->{$propertyName}) {
    $propertyValue = $this->{$propertyName};
} else {
    $propertyValue = null;
}

Another solution is to define private (or public) method $obj->getProperty($name) and call it from your callback through reflection and setAccessible. As soon as this method defined in original class it has access to all private members.

Upvotes: 0

Artefacto
Artefacto

Reputation: 97805

I'm afraid you can't. ReflectionProperty::getValue would have to return by reference for that to be possible, which it doesn't.

Upvotes: 1

Related Questions