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?

Original source