我有两个使用__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}";
作为旁注,这只是一个简单的例子,它展示了我在现实世界项目中看到的行为。谢谢!
答案 0 :(得分:2)
您遇到的问题是您尚未定义__unset()
魔术方法。
这意味着当您调用unset($myExample->my_property)
时,它会尝试直接取消设置具有指定名称的公共属性。
在示例1中,真正受保护的属性在其名称中有一个下划线。因此,当您尝试取消设置该属性时,PHP会查看该对象,发现没有指定名称的内容,并且实际上忽略了它。
如果你试图取消设置一个不存在的变量或数组元素,这与unset()
所表现的行为相同。
但是在示例2中,受保护的属性与您在unset()
调用中提供的名称相同。
在这个例子中,PHP查看对象并看到该属性确实存在,但它是不可访问的。因此,它会抛出一个错误,抱怨它无法取消该属性。
您可以通过在__unset()
和__get()
方法中加入__set()
方法来解决此问题。如果您计划使用魔术方法,理想情况下应该定义所有三种方法。
希望有所帮助。