Поиск в массиве
Гардеробщик умеет не только сортировать и отбирать вещи, но и искать их. Спросите его: «Есть ли у вас синее пальто?» — и он ответит «да» или «нет». Спросите: «На каком оно крючке?» — и он назовёт номер.
В PHP на первый вопрос отвечает функция in_array, на второй — array_search.
Как вы уже знаете, оператор == сравнивает нестрого: для него строка '10' и число 10 — одно и то же. Обе функции по умолчанию сравнивают именно так:
<?php
$allowed = ['10', '20', '30'];
var_dump(in_array(10, $allowed)); // bool(true)
var_dump(in_array(10, $allowed, true)); // bool(false)
var_dump(in_array('10', $allowed, true)); // bool(true)Давайте разберём по строкам:
$allowed— список разрешённых кодов. Это строки: так данные обычно приходят из формы или файла.in_array(10, $allowed)сравнивает через==и находит'10', поэтому возвращаетtrue, аvar_dumpпечатаетbool(true).- С третьим аргументом
trueсравнение идёт через===. Число10не равно строке'10', и ответ —bool(false). - Строка
'10'совпадает со строкой'10'и при строгом сравнении.
in_array: есть ли значение
in_array проверяет, есть ли значение среди значений массива, и возвращает true или false. На ключи она не смотрит.
Нестрогое сравнение по умолчанию
Без третьего аргумента каждое значение массива сравнивается с искомым через ==. Поэтому in_array('1e1', $allowed) тоже вернёт true. Обе строки, '1e1' и '10', числовые, а == сравнивает такие строки как числа: 1e1 — это 10.
Строгое сравнение с true
Третий аргумент true включает ===: совпадёт только значение того же типа. Белый список — перечень разрешённых значений: ролей, кодов, идентификаторов. Проверяя по нему, всегда передавайте true, иначе проверку пройдёт и '1e1', которого в списке нет.
Почему in_array без третьего аргумента опасна, часто спрашивают на собеседовании. Ответ: она сравнивает через ==, и проверку по белому списку проходят значения, которые лишь нестрого равны разрешённым.
array_search: где лежит значение
array_search ищет так же, как in_array, и понимает тот же третий аргумент. Но возвращает она не «да» или «нет», а ключ найденного элемента. Если значения нет, она возвращает false:
$days = ['mon', 'tue', 'wed'];
var_dump(array_search('tue', $days)); // int(1)
var_dump(array_search('mon', $days)); // int(0)
var_dump(array_search('sun', $days)); // bool(false)Обратите внимание на вторую строку. 'mon' висит на первом крючке, а номер у этого крючка — 0. Это настоящий ключ, и всё же в условии if число 0 ложно, как и false.
Поэтому результат array_search сравнивают строго: $pos === false значит «не нашли», а любое другое значение — ключ находки. Это ещё один классический вопрос собеседования: «Чем опасен if (array_search(…))?»
Здесь картинка с гардеробщиком неточна. Живой гардеробщик на вопрос «где пальто?» скажет «на первом крючке», а array_search назовёт номер 0, и этот ответ можно спутать с «нигде».
Ключ или значение
in_array и array_search ищут среди значений. Ключ проверяют isset и array_key_exists, а расходятся они на значении null. Для $stock = ['kiwi' => null] запись isset($stock['kiwi']) даёт false, а array_key_exists('kiwi', $stock) — true: ключ есть, а в нём лежит null.
Ещё пять помощников
На частые вопросы к массиву у PHP есть готовые ответы:
$visits = [3, 7, 3, 5, 7];
echo implode(' ', array_unique($visits)), "\n"; // 3 7 5
echo json_encode(array_unique($visits)), "\n"; // {"0":3,"1":7,"3":5}
echo max($visits), ' ', min($visits), "\n"; // 7 3
echo implode(' ', range(1, 5)), "\n"; // 1 2 3 4 5
echo array_key_first(['pear' => 7, 'kiwi' => 9]), "\n"; // peararray_uniqueубирает повторы и оставляет первое вхождение каждого значения вместе с его ключом. Поэтому, как и послеarray_filter, в нумерации остаются дыры.maxиminвозвращают самое большое и самое маленькое значение.range(1, 5)строит список чисел от1до5включительно.array_key_firstвозвращает первый ключ массива, а для пустого массива —null.
Частая ошибка
Результат array_search проверили обычным условием:
$queue = ['ann', 'bob', 'cat'];
$pos = array_search('ann', $queue);
if (!$pos) { // ✗
echo 'not in the queue', "\n";
}Программа печатает not in the queue, хотя 'ann' стоит в очереди первой, и PHP не выдаёт никаких сообщений. array_search вернула ключ 0, а !0 — это true. Исправление — строгая проверка: if ($pos === false).
Главное
in_arrayиarray_searchпо умолчанию сравнивают через==; третий аргументtrueвключает===.in_arrayотвечаетtrueилиfalse, аarray_searchвозвращает ключ найденного элемента илиfalse.- Ключ
0— настоящая находка, но вifон ложен, поэтому результатarray_searchпроверяют через=== false. array_unique,max,min,rangeиarray_key_firstотвечают на частые вопросы к массиву одной строкой.