Перейти к содержимому
Теория · Функции для массивов · урок 5 из 8

Поиск в массиве

Гардеробщик умеет не только сортировать и отбирать вещи, но и искать их. Спросите его: «Есть ли у вас синее пальто?» — и он ответит «да» или «нет». Спросите: «На каком оно крючке?» — и он назовёт номер.

В PHP на первый вопрос отвечает функция in_array, на второй — array_search.

Как вы уже знаете, оператор == сравнивает нестрого: для него строка '10' и число 10 — одно и то же. Обе функции по умолчанию сравнивают именно так:

PHP
<?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)

Давайте разберём по строкам:

  1. $allowed — список разрешённых кодов. Это строки: так данные обычно приходят из формы или файла.
  2. in_array(10, $allowed) сравнивает через == и находит '10', поэтому возвращает true, а var_dump печатает bool(true).
  3. С третьим аргументом true сравнение идёт через ===. Число 10 не равно строке '10', и ответ — bool(false).
  4. Строка '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:

PHP
$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 есть готовые ответы:

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"; // pear
  • array_unique убирает повторы и оставляет первое вхождение каждого значения вместе с его ключом. Поэтому, как и после array_filter, в нумерации остаются дыры.
  • max и min возвращают самое большое и самое маленькое значение.
  • range(1, 5) строит список чисел от 1 до 5 включительно.
  • array_key_first возвращает первый ключ массива, а для пустого массива — null.

Частая ошибка

Результат array_search проверили обычным условием:

PHP
$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 отвечают на частые вопросы к массиву одной строкой.