我最近与另一位开发人员就 PHP__isset()和__get()魔术方法之间的关系进行了简短的讨论。它是由我们拥有的一个类带来的,该类通过该__get()方法延迟加载其他对象(延迟加载意味着该属性在第一次访问之前不存在,此时对象被实例化并返回)。__isset()但是,对于尚未加载的属性应该返回什么,我们有不同的意见。该属性在技术上不存在(它不是set,或者至少,它是 set 但当前NULL),但是对它的调用在技术上也会成功(除非有任何异常)并返回一个非NULL值。
所以,我的问题是,在这种情况下,应该__isset()只是一个指示是否__get()会成功的同一个论点(TRUE如果__get()会成功,返回一个非NULL值)。或者,它是否应该在技术上表现得更好,并返回FALSE,因为数据尚不存在(即使第一次访问时它会存在)?
一个简单的例子:
class Foo {
protected $data;
public function __get($prop) {
if ($prop == 'bar') {
$this->data['bar'] = new Bar;
return $this->data['bar'];
}
}
public function __isset($prop) {
if ($prop == 'bar') {
// What goes here?
// return isset($this->data[$prop]) would mean
// that the first call to isset($foo->bar) below will be FALSE
// which means that using logic like this would always fail
// and __get() would never be called:
// isset($foo->bar) ? $foo->bar->baz : 'foo->bar not set'
}
}
}
class Bar {}
$foo = new Foo;
var_dump(isset($foo->bar)); // ???
$bar = $foo->bar;
var_dump(isset($foo->bar)); // bool(true)
Run Code Online (Sandbox Code Playgroud)
您必须从类的用户的角度考虑这一点。假设$foo是class Foo,并且您有以下代码:
if(isset($foo->bar)) {
var_dump($foo->bar); // #1
}
else {
// $foo->bar is "not set", right?
$x = $foo->bar;
var_dump($x); // #2
}
Run Code Online (Sandbox Code Playgroud)
反问:你希望#1 打印出来null吗?您是否希望 #2 打印除 之外的 任何内容null?
当然不是。如果它像那样工作,那么用户class Foo将花费大部分工作日来诅咒作者。
假设我已经说服了你,从期望的行为开始并回到应该如何实现它是非常简单的,即__isset像这样实现:
public function __isset($prop) {
$val = $this->$prop;
return isset($val);
}
Run Code Online (Sandbox Code Playgroud)