|
|||||||
Что не так с функцией array_key_exists() и имплементацией ArrayAccess в PHP5?
Время создания: 14.04.2017 17:49
Автор: Xintrea
Текстовые метки: PHP, PHP5, ArrayAccess, ArrayObject, array_key_exists, in_array
Раздел: Компьютер - Программирование - Язык PHP
Запись: xintrea/mytetra_syncro/master/base/1492181386xcu0bf53ck/text.html на raw.github.com
|
|||||||
|
|||||||
Интерфейс ArrayAccess - это хороший и быстрый способ создать объект, способный представить свое содержание как массив. В официальной документации все кратко и точно расписано. Но есть одно но. Если с таким объектом начинает работать функция array_key_exists(), то она не будет видеть элемента с существующим ключем. Почему так? Вот пример кода, поясняющего что происходит на самом деле: <?php
var_dump(array_key_exists('somekey', $a)); // returns false Здесь написана реализация переопределяемого метода offsetExists(). И, казалось бы, что функция array_key_exists() должна работать правильно. Но видно, что элемента с существующим ключем 'somekey' эта функция не видит. Зато видит элемент с несуществующим ключем 'data'. Почему так? Потому что эта функция является "осколком" интерфейсов, которые позволяют работать со свойствами и методами объекта как с итерируемыми сущностями. Функция array_key_exists() вообще не обращает внимание на реализацию offsetExists(), она работает совсем по-другому: проверяет наличие элемента класса (элементы класса - это свойства и методы класса). В нашем примере она находит публичное свойство $data, и поэтому считает, что у объекта есть элемент 'data'. Как же узнать, если ли в объекте-массиве настоящий элемент? Можно воспользоваться функцией isset: var_dump(isset($a['somekey'])); // returns true Однако в таком решении есть проблема: если значение элемента массива null, то несмотря на то что элемент существует, isset() вернет false. Все вышесказанные проблемы перечеркивают все достоинства наследования от ArrayAccess. UPD1: Говорят, что есть более правильное решение: воспрользоваться неаследованием от ArrayObject. У такого объекта будет работать не только доступ по скобкам, но и итерирование через foreach (если переопределить метод getIterator(). Но практика показала, что и для объекта, унаследованного от ArrayObject, функция array_key_exists() работает точно так же как и для ArrayAccess. UPD2: Единственное более-менее вменяемое решение данной проблемы следующее. Вместо array_key_exists() и in_array() можно написать специальные методы класса: // Equivalent of array_key_exists() public function arrayKeyExists($key) { return $this->offsetExists($key); }
// Equivalent of in_array() public function inArray($value) { return in_array($value, $this->array); } После чего можно использовать следующий код: var_dump( $a->arrayKeyExists('somekey') ); return true var_dump( $a->inArray(1) ); return true |
|||||||
Так же в этом разделе:
|
|||||||
|
|||||||
|