Блог Веб-разработчика.

В этой статье, я разберу одну достаточно частную и частую проблему, которая может возникнуть в процессе разработки на php. Эта проблема является отражением не столько проблем организации языка программирования php, сколько не полного  понимания некоторых особенностей этого языка начинающими программистами.

При работе в php очень часто приходится иметь дело с массивами, и в частности иногда встает задача поиска элемента в массиве, совпадающего с некоторым искомым значением. Для решения этой частной задачи, очень удобно пользоваться функцией:

Array_search ($needle , array $haystack)

Согласно документации php, функция осуществляет поиск по массиву $haystack и ищет в нем элемент, значение которого совпадает со значением $needle. В качестве результата, функция возвращает либо ключ элемента в массиве (читай «номер элемента в списке»), либо, если ничего не найдено - возвращает ошибку «false». В общем-то, кажется что все нормально и логично. Однако, могут возникать ситуации, когда ответы возвращаемые этой функцией могут ввести в заблуждение и приводить к ошибкам работы разрабатываемого скрипта. Приведу для наглядности конкретные примеры, когда array_search() как будто бы перестает работать.

Случай первый.

$goroda = array("Москва","Санкт-Питербург","Нижний Новгород");
$gorod = "Москва";
$result  = array_search($gorod, $goroda);
if ($result == false) {
  echo "
город не найден!";
} else {
  echo "
город найден!";
}
 

в результате исполнения кода получим на первый взгляд странный ответ – «город не найден». То есть элемент совпадающий с «Москва» в массиве есть, но он почему-то не «ищется» ….

Случай второй.

$bool = array("one"=>"элемент №1",""=>"элемент №2","two"=>"эдемент №3");
$needle = "элемент №2";
$result  = array_search($needle, $bool);
if ($result == false) {
  echo "
элемент не найден.";
} else {
  echo "
элемент найден.";
}
 

Аналогичная ситуация. Элемент в массиве совершенно очевидно присутствует, но в качестве результата мы получаем ответ, что «элемент не найден».

Случай третий.

$bool = array("one"=>"элемент №1","0"=>"элемент №2","two"=>"эдемент №3");
$needle = "элемент №2";
$result  = array_search($needle, $bool);
if ($result == false) {
  echo "
элемент не найден.";
} else {
  echo "
элемент найден.";
}
 

Аналогично – получаем ответ «элемент не найден».

Случай четвертый.

$bool = array(0.12=>"элемент №1",0.0=>"элемент №2",1.5=>"эдемент №3");
$needle = "элемент №2";
$result  = array_search($needle, $bool);
if ($result == false) {
  echo "
элемент не найден.";
} else {
  echo "
элемент найден.";
}
 

Тоже самое, при исполнении кода получим на мониторе «элемент не найден».

Случай пятый.

$bool = array(0.12=>"элемент №1",NULL=>"элемент №2",1.5=>"эдемент №3");
$needle = "элемент №2";
$result  = array_search($needle, $bool);
if ($result == false) {
  echo "
элемент не найден.";
} else {
  echo "
элемент найден.";
}
 

«И опять, двадцать пять»…. Как говорится.

Причина возникающей ошибки и ее решение.

На самом деле причина возникающих ошибок кроется не в самой функции array_search(), а в том какой результат она возвращает и как мы его проверяем. Дело в том, что в php, как и в большинстве других языков программирования, при обработке информации, важное значение имеет не только конкретное значение переменной, но и тип данных, к которым она относится.

В частности в данном случае, функция возвращает либо «false» (тип данных boolean), либо ключ элемента в массиве. Этот ключ может представлять собой или целое число (integer), или строку (string), или вещественное число с десятичной добью (float), или специфический тип данных, обозначающий неопределенное значение (NULL). И ошибка в выше приведенных примерах связана с тем, что некоторые значения не boolean  данных могут быть преобразованы в boolean. В частности, согласно самой справки php, следующие значение могут быть преобразованы в булев «false»:

  • само значение boolean FALSE
  • integer 0 (ноль)
  • float 0.0 (ноль)
  • пустая строка, и строка "0"
  • массив без элементов
  • объект без полей (только для PHP 4)
  • особый тип NULL (включая неустановленные переменные)
  • Объекты SimpleXML, созданные из пустых тегов
  • Все остальные значения рассматриваются как TRUE (включая любой resource).

Разберем каждый из перечисленных выше примеров.

Случай первый.

По умолчанию, нумерация ключей элементов массива начинается с 0, если не задано иначе специально. Соответственно, функция array_search() вернула правильный результат – номер ключа 0 (integer, целое число), но при сравнении этот результат был приведен к булеву «false», а это в свою очередь выполнило условие, что «элемент не найден».

Случай второй.

Заданы ключи элементов массива, которые являются строками, но при этом ключ искомого элемента равен пустой строке «». И при проверке условия, эта пустая строка была интерпретирована как булев «false», что опять же выполнило условие для вывода «элемент не найден».

Случай третий.

Ключи массива заданы строками, при этом ключ искомого элемента равен строке «0». Именно строке, не целому числу, а строке. Именно этот ключ функция вернула, но при проверке это значение было приведено к boolean «false».

Случай четвертый.

Ключи элементов массива заданы в виде чисел с плавающей точкой (float). Ключ целевого элемента массива оказался равен нулю (0.0), который при сравнении был рассмотрен как «false», что выполнило условие для вывода результата о том, что элемент в массиве не найден.

Случай пятый.

Думаю, что уже ясно. Там ключ нужного нам элемента массива задан специальным значением NULL, которое при сравнении в блоке условия было воспринято как булев «false» - ошибка.

Решение.

Решением данной ошибки, является более строгая проверка результата работы функции array_search(). Во всех перечисленных примерах выше проверялось лишь значение возвращенного результата, без проверки типа данных к которым относится полученный ответ. Поэтому для наглядности, следовало бы во всех выше перечисленных примерах вместо строки

if ($result == false) {

написать

if ($result == false and is_bool($result)) {

то есть в таком случае мы не только проверяем значение ответа функции, но и убеждаемся (в данном случае), что оно он относится к типу данных boolean.

Функция is_bool() проверяет – относится ли переданное ей значение к типу boolean.

Но, конечно же, обычно так условие никто не записывает. Так как есть специальный оператор «тождественно равно» (===) и ему противоположный «тождественно не равно» (!==). Это операторы строгой проверки, когда проверяется не только конкретное значение присланной переменной, но и тип ее данных. Поэтому для исправления ошибки во всех приведенных примерах, в блоке условия проверку следует переписать так:

if ($result === false) {

тогда мы начнем получать правильные ответы от работы кода.

Обобщение.

Вообще говоря, строгая проверка, о которой говорится в этой статье, полезна и для многих других функций php, которые могут возвращать либо ошибку «false», либо какое-то вычисленное, найденное, извлеченное значение… Потому, что иногда вычисленное, найденное, извлеченное значение может совпадать со значением «false», хотя и относиться к другому типу данных (то есть любой тип данных кроме boolean).

Например: mysql_query() функция осуществляет запрос к базе данных. И при запросах SELECT - в качестве ответа возвращает результат выборки из базы данных, либо «false» -  в случае ошибки. А если в целевой ячейке таблицы базы данных записано NULL, или 0, или  0.0, или «» (пустая строка, ничего не записано) – то при дальнейшей проверке мы можем опять же получить некорректную работу нашего скрипта. Чтобы этого не происходило, нужно опять же пользоваться оператором строго сравнения «===» или «!==».

Так что будьте внимательны. И не забывайте про типы данных, которые могут помещаться в переменные используемые в Вашем коде. И многих проблем можно избежать сразу.

Если информация этой статьи будет интересна и полезна Вашему кругу друзей и знакомых, то Вы можете опубликовать ссылку - тогда им проще будет ее найти. Они Вам будут благодарны:).

Комментарии к статье:


Всеволод Чупрыгин © webengineer.pro 2014. Все права защищены.
Копирование материалов сайта разрешено только с указанием имени автора (Всеволод Чупрыгин) и прямой индексируемой ссылки на источник на сайте www.WebEngineer.pro.
ИП Чупрыгин Всеволод Андреевич, ИНН: 333410747832, ОГРН: 311333426300044
http://vkontakte.ru/chuprygin_va, Google +

.
Проверить аттестат
Мы принимаем Webmoney Мы принимаем практически все платежи через Robokassa Мы принимаем Яндекс.Деньги Мы принимаем платежи через QIWI. Мы принимаем платежи через привязанные к QIWI карты VISA/Mastercard.