1

I came across the following code and could not figure out why the output of the script came out in a non-intuitive sequence using php's get and set magic methods.

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;

Out put was:

bcA,B,C,c
CCbcA,B,C

First of all why is it no outputting A as the first thing? The sequence of output doesn't make sense.

1
  • 3
    Damn give meaningful names to var and values please, it's a pain to the eye to read that. Commented Feb 19, 2013 at 13:30

3 Answers 3

1

The reason is quite simple. You do string concatenation so PHP has to prepare complete string before outputs one. It means that it executes everything that needs to be concatenated. When it executes getter (__get method will be called only for inaccessible members) there's echo that is executed first and then returned value.

If you echo them out separately everything will be on its place.

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

4 Comments

So you could say that it performs some sort of "preprocessing" before it outputs the whole evaluation.
@robertrocha Exactly. When strings are concatenated string from the left of concatenation operator is taken and is concatenated to the one from the right-side. If both strings are not known interpreter won't be able to concatenate them unless finds out what is a string that needs to be merged with another one.
I think I understand how it works now. The line of code is evaluated. Since the get, set methods execute an echo before the whole line gets echoed the order of display gets scrambled since these two methods bypassed, you could say, the parent echo and echoed on their own.
@robertrocha Yes, with a note that setter can't be used for concatenation since it should be void.
1

Somebody is studying for their Zend certification ;-)

The reason is that magic methods are only triggered when the property is inaccessible.

So, for the first echo, it fetches $m->a this is an accessible property, so it is not echo'd from __get and is simply returned. After this, both $b and $c are inaccessible, so they are echo'd and then returned.

So the output from the first echo is:

b // echo'd by __get
c // echo'd by __get
A // simply returned, and echo'd in the concatenated string
B // (As above)
C // (As above)

Comments

0
echo $m->a . "," . $m->b . "," . $m->c . ",";

When this line gets called, it is first resolving variable names before the concatenation takes place.

So it looks up $m->a, then $m->b, then $m->c.

Since $m->a resolves to your public property a, it doesn't trigger your _get, thus that echo in there doesn't get sent right away. However, $m->b does trigger it, which causes it to get echoed.

Finally, once the variables are resolved, the whole concatenated string gets output.

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.