Использование функций isset() и array_key_exists()
Навеяно проблемой, с которой я столкнулся из-за неправильного использования функции isset() в одном китайском движке интернет магазина. Там isset() применялась для определения существования элемента массива с некоторым ключом. Самое неприятное в данной ситуации то, что такую ошибку допускают многие. Это не первый случай, когда isset() используется именно в таком контексте, хотя это в корне неверно. Но в этот раз неграмотность разработчиков стоила мне потерянного времени, что и сподвигло меня на эту заметку.
Еще больше меня «порадовали» комментарии одного «незнакомого» знакомого, который удивился моему негодованию. Как оказалось, о существовании функции array_key_exists() он что-то слышал, но сам никогда ею не пользовался. Более того, где-то читал, что ее лучше заменять на isset() , так как последняя работает быстрее.
Собственно, об уровне квалификации PHP программистов сказано немало и добавить к этому нечего.
Инициализация и удаление переменной в PHPВ PHP переменная инициализируется в момент присваивания ей значения. Неинициализированной переменная считается в двух случаях:
- ей не присваивалось никакого значения;
- ей было присвоено значение типа NULL или она была передана функции unset() .
Присваивание NULL значения удаляет переменную, аналогично функции unset() , то есть делает ее неинициализированной.
Если попытаться использовать переменную, которая была удалена с помощью unset() , будет сгенерирована ошибка уровня E_NOTICE. С переменной, приведенной к NULL, такого не произойдет.
Функция isset()Функция проверяет факт инициализации переменной. isset() вернет false, если передать ей в качестве параметра неинициализированную переменную. Тоже самое произойдет и с ключом массива, который имеет NULL значение. Для ключей массива действуют такие же правила приведения к NULL, как и для переменных.
Результат:
Функция array_key_exists()Работа функции array_key_exists() похожа на isset() , но с той лишь разницей, что даже для ключа с NULL значением будет возвращено TRUE.
Чтобы полностью удалить пару ключ-значение необходимо использовать unset() .
Для массива использование NULL значения ключа удобно, если наличие ключа требуется сохранить. Можно будет рассчитывать на контекст, в котором данный ключ будет использован. Например, это удобно при заполнении полей формы дефолтными значениями. Например, при использовании конструкции echo, NULL значение будет приведено к пустой строке.
То, к чему я клоню, мне кажется очевидным. Если вы работаете с ключами массива, то используйте именно ту функцию, которая для этого предназначена. Ко всему прочему, использование array_key_exists() позволяет точно понять логику приложения. Никакой двусмысленности не возникает.
Скорость работы isset() и array_key_exists()О том, что array_key_exists() работает медленнее isset() пишут даже в комментариях к соответствующей странице PHP мануала. Жалуются на то, что более медленная работа array_key_exists() заметна на массивах с количеством пар ключ-значение, превышающих 200.
Ничего не остается, как прогнать банальный тест:
Ассоциативный массив $testArray содержит 10 000 элементов. Это несколько больше, чем упомянутые 200.
Далее прогоняем цикл с количеством итераций 100 000. В теле цикла, по очереди, сначала делаем проверку с помощью isset() , затем с помощью array_key_exists() . Ключ, наличие которого проверяем, генерируется случайным образом, чтобы свести к минимуму вероятность его существования в массиве.
isset() array_key_exists() 0.687027 0.728652
Тест, безусловно, очень простой и достаточно субъективный. Было бы неплохо сделать замеры используемой памяти, например. Но глядя на результаты этого теста, у меня нет никакого желания продолжать заниматься мышиной возней. Очевидно, что выигрыша в скорости попросту нет.
Функция isset() и свойства объектаСовсем клиническим случаем можно считать использование isset() для проверки существования свойства у объекта.
Не так часто, как в случае с массивами, но доводится встречать подобные условия:
Случай вопиющий, так как использование NULL в качестве дефолтного значения свойств – очень распространенная практика. И проверять наличие свойства объекта через isset() просто недопустимо.
Для проверки существования свойства у объекта в PHP существует функция property_exists() . Как и array_key_exists() , property_exists() вернет TRUE даже в том случае, если значение свойства приведено к NULL.
Также замечу, что для использования property_exists() не требуется наличие объекта класса. Проверку можно произвести по имени класса и имени свойства.
Такое вот занимательное программирование.
Комментарии (6)Вечер добрый! Очень классные статьи, большое спасибо за них!
Насчет функции isset. А если такой случай — есть функция getUsers($data), которая возвращает пользователей из БД. Если передано значение $data[‘where’] (ассоциативный массив по которому происходит фильтрация), то произвести фильтрацию. У меня в коде if (isset($data[‘where’])), в данном случае я верно пишу? Т.к. мне нужно знать не только существует ли ключ но так же чтобы у него было значение. (Кстати, тогда даже наверно if (is_array($data[‘where’])) т.к. ф-ии нужно передавать именно ассоциативный массив)
Вы все верно поняли. На самом деле, практически повсеместно используется isset(). Иногда из-за этого возникают логические ошибки в приложениях, что и стало причиной написания данной заметки.
Не надо людей вводить в заблуждение и навязывать свои ошибочные мысли. В мануале от создателей PHP явно сказано, что isset используется и для проверки элементов массива. И это правильно. А вот использовать элемент массива с NULL и считать этот элемент существующим, это ошибка. Вот из-за таких как ты и приходится потом сутками сидеть и разгребать больные коды и не понимать, почему же блин переменные NULL существуют.
Максим, во-первых, я вам вам не «ты». А во-вторых, мир сложнее, чем вам кажется и нужно беречь свои нервы, а то не хватит сил на разгребание больных кодов :)) И если NULL значение в массиве — это ошибка, то это ошибка в интерпретаторе PHP. Но, думаю, дело все в том, что вы просто не понимаете смысл типа данных NULL.
Олег, вы не правы в ряде моментов. Не стоит «гнать» на PHP разработчиков, т.к. те кто ними являются, пишут хороший код. А то, что вы всех, кто написал строчку кода на PHP называете PHP-программистом, это лично ваши «психо-половые» проблемы. Второй момент, насчет NULL: в языке PHP смысл языковой конструкции null отличается от той же конструкции SQL … и не стоит и пытаться друг на друга «натягивать». Это не проблема языка, т.к. авторы языка вольны толковать как им вздумается «сколько людей, столько и мнений.». Третий момент, если Вы знаете, что PHP-разработчики пишут плохой код, то зачем вы его используете? Пишите сами или используете код других языков. Я могу понять, что писали вы пост под влиянием эмоций, но я так и не понял, что было не так в том коде «китайского движка» и что у вас не выходило? :) Напишите название движка, чтобы люди знали о том, и что тут могут вылезти проблемы при использовании и место возникновения проблемы.