PHP变量可见性和魔术方法的行为

时间:2014-01-21 08:48:44

标签: php visibility magic-methods zend-certification

此问题与:PHP magic methods example

有关

我在接受的答案中已经在评论中提出这个问题,但我想,它没有被注意到所以我必须创建这个问题。

<?php
    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;
?>

输出: b,c,A,B,C,c: CC,b,c,A,B,C

$m->c = "CC";这里我们已经有了同名的受保护变量。 那么,这应该如何在可见性的背景下表现呢?

如果它覆盖了受保护变量c的值,那么它不是受保护/私有变量的循环漏洞吗? (我猜不会是这种情况)

如果没有,语句:$this->$var = $val;似乎创建了具有相同名称的公共变量,已经定义为protected。 这可能吗?

此后,在此声明之后:$m->c = "CC";,当我们再次访问$m->c时,PHP再次调用__get,就像c没有公开可见性一样。 这是否意味着$this->$var = $val;没有终身下一次陈述的生命时间? (我想也不会这样)

任何人都可以解释一下,它应该在这种情况下表现出来以及它是如何产生这样的输出的吗?

2 个答案:

答案 0 :(得分:2)

看起来c仅通过方法进行更改。虽然它受到保护,但神奇的方法暴露了它。

如果你看一下这个例子:

class Magic
{
    protected $b = 'B';

    public function __get($v)
    {
        return 'C';
    }

    public function __set($v, $val)
    {
        $this->$v = $val;
    }
}

$magic->b = 'D';
echo $magic->b; // Outputs: C

第一次调用会将属性b设置为D,但由于getter已经过硬编码以返回C,因此仍然会尊重protected访问修饰符。< / p>

EDIT。

魔术getter / setter的另一个用途是访问集合。这个例子展示了它们的灵活性:

class Magic
{
    private $properties = array();

    public function __get($key)
    {
        if(isset($this->properties[$key])) {
            return $this->properties[$key];
        }
    }

    public function __set($key, $value)
    {
        $this->properties[$key] = $value;
    }

    public function dump($return = false)
    {
        if($return) {
            return print_r($this->properties, true);
        } else {
            print_r($this->properties);
        }
    }
}

$magic = new Magic();

$magic->a = '123';
$magic->b = '456';
$magic->c = '789';

echo '<pre>';

echo sprintf('A: %s%s', $magic->a, PHP_EOL);
echo sprintf('B: %s%s', $magic->b, PHP_EOL);
echo sprintf('C: %s%s', $magic->c, PHP_EOL);

echo PHP_EOL;

echo $magic->dump(true);

输出:

A: 123
B: 456
C: 789

Array
(
    [a] => 123
    [b] => 456
    [c] => 789
)

它们只是函数,因此遵循相同的规则,唯一的区别是它们被调用的方法。

答案 1 :(得分:1)

你的getter和setter都适用于不同的变量。

getter访问属性$ b的元素 setter直接访问指定的属性。

可见性在这里无关紧要,因为您的所有访问都是从类的方法发生的。因此,他们能够毫无差别地访问公共和受保护的属性。

将魔术函数视为具有奇怪名称的普通函数。这与以这种方式访问​​它们相同:

$m->__get("a");
$m->__set("c", "CC");