2012-03-05 1 views
1

Недавно я недавно поговорил с другим разработчиком о взаимоотношениях между методами PHPи __get(). Это было вызвано классом, который у нас есть, который ленивы нагружает другие объекты с помощью метода __get() (lazy-load означает, что свойство не существует до первого доступа, после чего объект создается и возвращается). У нас были разные мнения о том, что __isset() должен вернуться для свойства, которое еще не загружено. Свойство технически не существует (это не набор, или, по крайней мере, он установлен, но в настоящее время NULL), но вызов ему также будет технически успешным (запрет любых исключений) и возвращает значение не NULL ,PHP: Отношения между __isset() и __get()

Итак, мой вопрос, в этой ситуации должна __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) 
+3

'__isset' должен проверить значение, возвращаемое' __get', чтобы узнать, установлено ли оно – zzzzBov

ответ

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); 
} 
+0

+1 хорошая примерная функция, иллюстрирующая то, что конечный пользователь, вероятно, проверяет. –

+0

Это то, к чему я склоняюсь, за исключением причудливой природы 'isset()' по отношению к значениям «NULL». Например, если класс 'Foo' имеет свойство' public $ foo = NULL; '- что ожидается, когда вы делаете что-то вроде isset ($ foo-> foo)'? Свойство * существует *, но оно не имеет значения, поэтому общие ожидания большинства разработчиков PHP, знакомых с тем, как работает 'isset()', это то, что он должен быть FALSE, поскольку он не имеет значения. Точно так же, если '$ foo' загружен ленивым, мы знаем, что свойство * существует *, но оно еще не имеет значения. В этом заключается мое замешательство в том, что он должен вернуть. – FtDRbwLXw6

+0

@drrcknlsn: Собственно, существует ли свойство * существует *, и это, вероятно, просто вас путает. Поскольку 'isset' возвращает' false' для значения «null», которое может очень «существовать», мы должны следовать примеру, нравится нам это или нет. Если 'null' является юридическим значением для свойства и поэтому не подходит для использования в качестве охранника, просто добавьте другое свойство, например. 'private $ gotFoo = false;', чтобы отметить, действительно ли вы уже выполняли ленивую загрузку. – Jon

0

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

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

Запрашивается ли объект недвижимости, а не null? Затем загрузите значение и верните результат.

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

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

+0

Использование будет зависеть от вызывающего кода, который я не контролирую и не понимаю, поскольку это класс библиотеки. По сути, я пытаюсь создать поведение, которое было бы самым ожидаемым * для других разработчиков, если это имеет смысл. – FtDRbwLXw6

+0

@drrcknlsn Я все еще думаю, что имеет смысл рассмотреть вопрос об использовании. Класс ActiveRecord имеет разные соображения, чем оболочка API. –

+0

@drrcknlsn И поскольку это библиотека, самая важная часть - это * document *, что означает 'isset()'. Проверяет ли оно, что значение * загружено *? Если значение было * установлено * (независимо от того, установлено ли оно «null»)? Или если свойство является * действительным * свойством? –

Смежные вопросы