I know this question has been asked several times, but none of them have a real answer for a workaround. Maybe there's one for my specific case.
I'm building a mapper class which uses the magic method __get()
to lazy load other objects. It looks something like this:
public function __get ( $index ) { if ( isset ($this->vars[$index]) ) { return $this->vars[$index]; } // $index = 'role'; $obj = $this->createNewObject ( $index ); return $obj; }
In my code I do:
$user = createObject('user'); $user->role->rolename;
This works so far. The User
object doesn't have a property called 'role', so it uses the magic __get()
method to create that object and it returns its property from the 'role' object.
But when i try to modify the 'rolename':
$user = createUser(); $user->role->rolename = 'Test';
Then it gives me the following error:
Notice: Indirect modification of overloaded property has no effect
Not sure if this is still some bug in PHP or if it's "expected behaviour", but in any case it doesn't work the way I want. This is really a show stopper for me... Because how on earth am I able to change the properties of the lazy loaded objects??
EDIT:
The actual problem only seems to occur when I return an array which contains multiple objects.
I've added an example piece of code which reproduces the problem:
http://codepad.org/T1iPZm9t
You should really run this in your PHP environment the really see the 'error'. But there is something really interesting going on here.
I try to change the property of an object, which gives me the notice 'cant change overloaded property'. But if I echo the property after that I see that it actually DID change the value... Really weird...
All you need to do is add "&" in front of your __get function to pass it as reference:
public function &__get ( $index )
Struggled with this one for a while.
Nice you gave me something to play around with
Run
class Sample extends Creator { } $a = new Sample (); $a->role->rolename = 'test'; echo $a->role->rolename , PHP_EOL; $a->role->rolename->am->love->php = 'w00'; echo $a->role->rolename , PHP_EOL; echo $a->role->rolename->am->love->php , PHP_EOL;
Output
test test w00
Class Used
abstract class Creator { public function __get($name) { if (! isset ( $this->{$name} )) { $this->{$name} = new Value ( $name, null ); } return $this->{$name}; } public function __set($name, $value) { $this->{$name} = new Value ( $name, $value ); } } class Value extends Creator { private $name; private $value; function __construct($name, $value) { $this->name = $name; $this->value = $value; } function __toString() { return (string) $this->value ; } }
class Sample extends Creator { } $a = new Sample (); $a->role = array ( "A", "B", "C" ); $a->role[0]->nice = "OK" ; print ($a->role[0]->nice . PHP_EOL); $a->role[1]->nice->ok = array("foo","bar","die"); print ($a->role[1]->nice->ok[2] . PHP_EOL); $a->role[2]->nice->raw = new stdClass(); $a->role[2]->nice->raw->name = "baba" ; print ($a->role[2]->nice->raw->name. PHP_EOL);
Output
Ok die baba
Modified Class
abstract class Creator { public function __get($name) { if (! isset ( $this->{$name} )) { $this->{$name} = new Value ( $name, null ); } return $this->{$name}; } public function __set($name, $value) { if (is_array ( $value )) { array_walk ( $value, function (&$item, $key) { $item = new Value ( $key, $item ); } ); } $this->{$name} = $value; } } class Value { private $name ; function __construct($name, $value) { $this->{$name} = $value; $this->name = $value ; } public function __get($name) { if (! isset ( $this->{$name} )) { $this->{$name} = new Value ( $name, null ); } if ($name == $this->name) { return $this->value; } return $this->{$name}; } public function __set($name, $value) { if (is_array ( $value )) { array_walk ( $value, function (&$item, $key) { $item = new Value ( $key, $item ); } ); } $this->{$name} = $value; } public function __toString() { return (string) $this->name ; } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With