PHP魔术方法在动态构建属性名称时表现不同


PHP magic methods behave differently when dynamically building property names

我有两个使用__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}";

顺便说一句,这只是一个简单的例子,展示了我在现实世界项目中看到的行为。谢谢

问题是您没有定义__unset()魔术方法。

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

在示例1中,真正受保护的财产的名称中有一个下划线。因此,当您尝试取消设置属性时,PHP会查看对象,发现没有指定名称,并有效地忽略它

这与unset()在尝试取消设置不存在的变量或数组元素时表现出的行为相同。

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

在本例中,PHP查看对象,发现该属性确实存在,但它是不可访问的。因此,它抛出一个错误,抱怨无法取消设置属性。

您可以通过将__unset()方法与__get()__set()方法一起包含来解决此问题。如果你打算使用神奇的方法,你应该理想地定义这三种方法。

希望能有所帮助。