动态构建属性名称时,PHP魔术方法的行为会有所不同

时间:2013-09-04 15:10:53

标签: php getter-setter magic-methods

我有两个使用__set()__get()魔术方法的简单类的示例。当尝试使用unset()函数访问受保护的属性时,一个抛出致命错误而另一个不抛出。

在示例1中,我使用下划线命名我的受保护属性开头,并允许通过友好名称进行访问,并在我的__set()__get()方法中添加下划线。 (在没有下划线的情况下有效地暴露财产)。

在示例2中,我使用下划线开始名称,并允许直接在__set()__get()方法中通过名称进行访问。

问题

1)为什么示例1 会抛出致命错误而示例2 会抛出致命错误?我希望两者都抛出错误或两者都不抛出错误。

2)另外,为什么示例1 实际上取消了该属性?我希望在调用unset()函数后该属性不包含值。

示例1

class Example {

    protected $_my_property;

    function __get($name) {
        echo '<h4>__get() was triggered!</h4>';
        $name = '_' . $name;
        if (property_exists($this, $name)) {
            return $this->$name;
        }
        else {
            trigger_error("Undefined property in __get(): $name");
            return NULL;
        }
    }

    function __set($name, $value) {
        echo '<h4>__set() was triggered!</h4>';
        $name = '_' . $name;
        if (property_exists($this, $name)) {
            $this->$name = $value;
            return;
        }
        else {
            trigger_error("Undefined property in __set(): {$name}");
        }
    }

}

$myExample = new Example();
$myExample->my_property = 'my_property now has a value';
echo $myExample->my_property;
unset($myExample->my_property);
echo "Did I unset my property?: {$myExample->my_property}";

示例2

class Example {

    protected $my_property;

    function __get($name) {
        echo '<h4>__get() was triggered!</h4>';
        if (property_exists($this, $name)) {
            return $this->$name;
        }
        else {
            trigger_error("Undefined property in __get(): $name");
            return NULL;
        }
    }

    function __set($name, $value) {
        echo '<h4>__set() was triggered!</h4>';
        if (property_exists($this, $name)) {
            $this->$name = $value;
            return;
        }
        else {
            trigger_error("Undefined property in __set(): {$name}");
        }
    }

}

$myExample = new Example();
$myExample->my_property = 'my_property now has a value';
echo $myExample->my_property;
unset($myExample->my_property);
echo "Did I unset my property?: {$myExample->my_property}";

作为旁注,这只是一个简单的例子,它展示了我在现实世界项目中看到的行为。谢谢!

1 个答案:

答案 0 :(得分:2)

您遇到的问题是您尚未定义__unset()魔术方法。

这意味着当您调用unset($myExample->my_property)时,它会尝试直接取消设置具有指定名称的公共属性。

在示例1中,真正受保护的属性在其名称中有一个下划线。因此,当您尝试取消设置该属性时,PHP会查看该对象,发现没有指定名称的内容,并且实际上忽略了它。

如果你试图取消设置一个不存在的变量或数组元素,这与unset()所表现的行为相同。

但是在示例2中,受保护的属性与您在unset()调用中提供的名称相同。

在这个例子中,PHP查看对象并看到该属性确实存在,但它是不可访问的。因此,它会抛出一个错误,抱怨它无法取消该属性。

您可以通过在__unset()__get()方法中加入__set()方法来解决此问题。如果您计划使用魔术方法,理想情况下应该定义所有三种方法。

希望有所帮助。