我有两个使用__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()
方法一起包含来解决此问题。如果你打算使用神奇的方法,你应该理想地定义这三种方法。
希望能有所帮助。