Magic getter/setter not being called
echo, oop, php
Solution
`__get` is only invoked for non-existent or invisible properties. In other words, when you write
$obj->prop
if `prop` is defined and is visible in the current context, it will be returned "as is", without calling `__get`.
Example:
class X {
public $pub = 1;
private $pri = 2;
function __get($v) {
echo "[get $v]\n";
return 42;
}
function test() {
echo $this->foo, "\n"; // __get invoked
echo $this->pri, "\n"; // no __get
echo $this->pub, "\n"; // no __get
}
}
$x = new X;
$x->test();
echo $x->foo, "\n"; // __get invoked
echo $x->pri, "\n"; // __get invoked (property not visible)
echo $x->pub, "\n"; // no __get
This explains why `magic->a` doesn't invoke the getter. Now, since you also have the setter defined, `magic->c = CC` actually changes the protected member of the class, therefore, when you echo `magic->c` later on, this still invokes the getter (due to `c`'s invisibility), and the getter returns `this->b[c]`, not the actual value of `this->c`.
Here's your code, slightly rewritten for clarity:
class Magic
{
public $a = "publicA";
protected $values = array( "a" => "valA" , "b" => "valB" , "c" => "valC" );
protected $c = "oldC";
public function __get( $v )
{
echo "[get $v]\n";
return $this->values[$v];
}
public function __set( $var , $val )
{
echo "[set $var=$val]\n";
$this->$var = $val;
}
}
$m = new Magic();
echo $m->a . ", " . $m->b . ", " . $m->c . "\n";
$m->c = "newC";
echo $m->a . ", " . $m->b . ", " . $m->c . "\n";
Results:
[get b]
[get c]
publicA, valB, valC # no getter for `a`
[set c=newC]
[get b]
[get c] # getter still invoked for `c`
publicA, valB, valC # no getter for `a`
An exercise to the reader:
Why is the output different if you replace dots `.` in the echo statements with commas:
$m = new Magic();
echo $m->a , ", " , $m->b , ", " , $m->c , "\n";
$m->c = "newC";
echo $m->a . ", " , $m->b , ", " , $m->c , "\n";
Problem
When I was reading the OOP chapter in the Zend PHP Certification study guide, 5.5, I found a question that gave me a shock from its answer. This question is: ``` class Magic { public $a = "A"; protected $b = array( "a" => "A" , "b" => "B" , "c" => "C" ); protected $c = array( 1 , 2 , 3 ); public function __get( $v ) { echo "$v"; return $this->b[$v]; } public function __set( $var , $val ) { echo "$var: $val,"; $this->$var = $val; } } $m = new Magic(); echo $m->a . ", " . $m->b . ", " . $m->c . ", "; $m->c = "CC"; echo $m->a . ", " . $m->b . ", " . $m->c . ", "; ``` The output for this code is: ``` b, c, A, B, C, c: CC, b, c, A, B, C ``` Why does this code not print `a`, and how does it work?