douxi8119 2014-11-22 12:47
浏览 45
已采纳

魔术吸气剂/定型器未被调用

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?

  • 写回答

4条回答 默认 最新

  • 普通网友 2014-11-22 13:03
    关注

    __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]
    ";
            return 42;
        }
    
        function test() {
            echo $this->foo, "
    ";  // __get invoked
            echo $this->pri, "
    ";  // no __get
            echo $this->pub, "
    ";  // no __get
    
        }
    }
    
    $x = new X;
    $x->test();
    
    echo $x->foo, "
    "; // __get invoked
    echo $x->pri, "
    "; // __get invoked (property not visible)
    echo $x->pub, "
    "; // 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]
    ";
            return $this->values[$v];
        }
    
        public function __set( $var , $val )
        {
            echo "[set $var=$val]
    ";
            $this->$var = $val;
        }
    }
    
    $m = new Magic();
    echo $m->a . ", " . $m->b . ", " . $m->c . "
    ";
    $m->c = "newC";
    echo $m->a . ", " . $m->b . ", " . $m->c . "
    ";
    

    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 , "
    ";
    $m->c = "newC";
    echo $m->a . ", " , $m->b , ", " , $m->c , "
    ";
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(3条)

报告相同问题?

悬赏问题

  • ¥15 基于卷积神经网络的声纹识别
  • ¥15 Python中的request,如何使用ssr节点,通过代理requests网页。本人在泰国,需要用大陆ip才能玩网页游戏,合法合规。
  • ¥100 为什么这个恒流源电路不能恒流?
  • ¥15 有偿求跨组件数据流路径图
  • ¥15 写一个方法checkPerson,入参实体类Person,出参布尔值
  • ¥15 我想咨询一下路面纹理三维点云数据处理的一些问题,上传的坐标文件里是怎么对无序点进行编号的,以及xy坐标在处理的时候是进行整体模型分片处理的吗
  • ¥15 CSAPPattacklab
  • ¥15 一直显示正在等待HID—ISP
  • ¥15 Python turtle 画图
  • ¥15 stm32开发clion时遇到的编译问题