6

Having done a bit of research, I eventually came across the answer to a question I was soon to ask here anyways; How do you work with arrays via the __get and __set magic methods in PHP? Whenever I was trying to set a value using something like $object->foo['bar'] = 42; it seemed to silently discard it.

Anyways, the answer is simple; The __get method simply needs to return by reference. And after tossing an ampersand in front of it, sure enough it works.

My question actually, is why? I can't seem to understand why this is working. How does __get returning by reference affect __set working with multidimensional arrays?

Edit: By the way, running PHP 5.3.1

1
  • It seems in PHP 5.2.x making __get return a reference doesn't help. Commented Jun 9, 2011 at 19:58

3 Answers 3

4

In PHP when you return a value from a function you can consider it making a copy of that value (unless it's a class). In the case of __get unless you return the actual thing you want to edit, all the changes are made to a copy which is then discarded.

Sign up to request clarification or add additional context in comments.

2 Comments

Ah, so in the process of setting a value, prior to __set being called, __get is called to retrieve (or check) the existence of the object variable?
$object->foo['bar'] = 42; never calls set. Set is called when your do something like $object->key = $value, but not when you do $object->key[$key2] = $value. This is because $object->key[$key2] is resolved using __get and then altered. So you can think of it like $magic_get_value = $value.
3

In this particular case, __set is not actually getting called. If you break down what it happening, it should make a bit more sense:

$tmp = $object->__get('foo');
$tmp['bar'] = 42

If __get did not return a reference, then instead of assigning 42 to the 'bar' index of the original object, you're be assigning to the 'bar' index of a copy of the original object.

Comments

2

maybe more clear:

//PHP will try to interpret this:
$object->foo['bar'] = 42

//The PHP interpreter will try to evaluate first 
$object->foo

//To do this, it will call 
$object->__get('foo')
// and not __get("foo['bar']"). __get() has no idea about ['bar']

//If we have get defined as &__get(), this will return $_data['foo'] element 
//by reference.
//This array element has some value, like a string: 
$_data['foo'] = 'value';

//Then, after __get returns, the PHP interpreter will add ['bar'] to that
//reference.
$_data['foo']['bar']

//Array element $_data['foo'] becomes an array with one key, 'bar'. 
$_data['foo'] = array('bar' => null)

//That key will be assigned the value 42
$_data['foo']['bar'] = 42

//42 will be stored in $_data array because __get() returned a reference in that
//array. If __get() would return the array element by value, PHP would have to 
//create a temporary variable for that element (like $tmp). Then we would make 
//that variable an array with $tmp['bar'] and assign 42 to that key. As soon 
//as php would continue to the next line of code, that $tmp variable would 
//not be used any more and it will be garbage collected.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.