PHP:__ isset()和__get()之间的关系

时间:2012-03-05 14:03:49

标签: php magic-methods

我最近与其他开发人员就PHP的__isset()__get()魔术方法之间的关系进行了简短的讨论。它是由我们通过__get()方法延迟加载其他对象的类引起的(延迟加载意味着该属性在首次访问之前不存在,此时对象被实例化并返回) 。不过,我们对于__isset()应该为尚未加载的属性返回的内容有不同的看法。从技术上讲,该属性不存在(它不是 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)

2 个答案:

答案 0 :(得分:4)

您必须从该类的用户的角度考虑这一点。假设$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
}

修辞问题:你会期望#1打印null吗?您是否希望#2打印 null以外的任何

当然不是。如果它像那样工作,那么class Foo的用户将花费大部分工作时间来诅咒作者。

假设我已经说服了你,从所期望的行为开始并回到应该如何实现它是很简单的,即像这样实现__isset

public function __isset($prop) {
    $val = $this->$prop;
    return isset($val);
}

答案 1 :(得分:0)

我认为这取决于isset()检查对您的代码的意义。使用isset()的代码实际上关心什么?

是否只是要求财产是价值(如,可以访问)?然后检查是否可以通过__get()访问该值并返回结果。

是否询问该属性是否有效而不是null?然后实际加载该值并返回结果。

是否询问该值是否已加载?然后检查是否已调用__get(),并返回结果。

但它应该反映你的课程的使用,而不是一些任意的规则。