PHP: связь между __isset () и __get () - PullRequest
1 голос
/ 05 марта 2012

Недавно я коротко обсудил с другим разработчиком взаимосвязь магических методов PHP __isset() и __get(). Это было вызвано тем классом, который у нас есть, который лениво загружает другие объекты с помощью метода __get() (ленивая загрузка означает, что свойство не существует до первого обращения, и в этот момент объект создается и возвращается). У нас были разные мнения относительно того, что __isset() должно возвращаться для свойства, которое еще не загружено. Свойство технически не существует (оно не установлено или, по крайней мере, оно установлено, но в настоящее время 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 ]

4 голосов
/ 05 марта 2012

Вы должны рассмотреть это с точки зрения пользователя класса.Предположим, что $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);
}
0 голосов
/ 05 марта 2012

Я думаю, это зависит от того, что означает проверка isset() для вашего кода.Что на самом деле волнует код, использующий isset()?

Это просто вопрос о значении свойства (например, можно получить доступ)?Затем проверьте, можно ли получить доступ к значению через __get(), и верните результат.

Спрашивает, действительно ли свойство действительно, а не null?Затем на самом деле загрузить значение и вернуть результат.

Он спрашивает, было ли загружено значение?Затем проверьте, вызван ли __get(), и верните результат.

Но это должно отражать использование вашего класса, а не какое-то произвольное правило.

...