Почему in_array() иногда ведет себя так странно и возвращает такие неожиданные результаты?
Давайте рассмотрим несколько примеров:
$arrayWithTrue = ['Andreas', 'Philipp', true]; $arrayWithNull = [1, 2, 3, null]; $arrayWithMinusOne = [-1]; var_dump(in_array('Gary', $arrayWithTrue)); // returns bool(true) var_dump(in_array(0, $arrayWithNull)); // returns bool(true) var_dump(in_array(true, $arrayWithMinusOne)); // returns bool(true)
А? Что тут происходит!?
(Несколько лет назад я подумал об этом, поначалу, о странном поведении. Я думал, что это может быть полезно для некоторых людей, поэтому я ввел этот вопрос.)
Используйте in_array() всегда с третьим параметром strict true :
$arrayWithTrue = ['Andreas', 'Philipp', true]; $arrayWithNull = [1, 2, 3, null]; $arrayWithMinusOne = [-1]; var_dump(in_array('Gary', $arrayWithTrue, true)); // returns bool(false) var_dump(in_array(0, $arrayWithNull, true)); // returns bool(false) var_dump(in_array(true, [-1], true)); // returns bool(false)
Поэтому, когда вы используете in_array() с true качестве третьего параметра, сравнение между искомым значением и массивом выполняется строго, что означает, что in_array() работает так, как вы, вероятно, ожидаете этого.
(Параметр strict также описан в документации php.net .)
Без параметра strict, установленного в true, сравнение найденного значения и каждого значения массива выполняется с помощью равенства, а не идентификатора. Это означает, что тип значения не имеет значения, и, таким образом, PHP преобразует значения внутри одного и того же типа данных, чтобы иметь возможность сравнивать их.
Это означает, что в первом примере искомое значение 'Gary' преобразуется в логическое, когда оно сравнивается с true , поэтому оно приводит к сравнению true с true , что, очевидно, true .
То же самое происходит со вторым массивом, где 0 , наконец, сравнивается с null , в результате получается true , хотя значение 0 , очевидно, не совпадает с null (это может быть особенно сложно, когда вы работаете с числами и / или результатами функции, например, где null может выразить пустое значение, а не 0 ).
Третий массив выглядит действительно странно, потому что мы проверяем значение true в массиве, которое содержит только -1 , но in_array() прежнему возвращает true для сравнения. В этом случае -1 преобразуется в логическое значение true . Таким образом, проблема в обоих направлениях одинакова.
Вы можете найти больше примеров проблемы сравнения в PHP (потому что это то же самое, что и == / === ) в этом ответе переполнения стека .
К сожалению, по умолчанию для строкового параметра при вызове in_array() есть … ну, да, false . : – / PHP и набирает текст …
Вы действительно никогда не должны называть in_array() без строкового параметра, установленного в true . Когда у вас нет массивов смешанных типов, и вы проверяете только значения одного типа, in_array() работает так, как ожидалось. См. Этот пример:
$arrayWithStrings = ['Andreas', 'Philipp', 'Friedrich']; var_dump(in_array('Gary', $arrayWithStrings)); // returns bool(false)
По крайней мере, это работает так, как ожидалось. Но, на мой взгляд, гораздо проще просто вызвать in_array() со строгой true . (Совместим с проблемой SQL Injection … Просто всегда используйте PDO и подготовленные операторы, чтобы вы были в безопасности, даже если это запрос без переменных параметров. Тогда вы всегда в безопасности.)
Вы должны обязательно вызвать in_array() со строгим значением true . Но есть один недостаток, хотя я хочу упомянуть (хотя это очевидно). Вы должны обязательно использовать правильные типы при вызове in_array() затем:
$arrayWithNumbers = [1, 2, 3]; var_dump(in_array('1', $arrayWithNumbers, true)); // returns bool(false)
Но вы можете просто использовать Type Casting, когда знаете, что сравниваете числа:
$arrayWithNumbers = [1, 2, 3]; var_dump(in_array((int)'1', $arrayWithNumbers, true)); // returns bool(true)
// Comparing false with an empty array var_dump(in_array(false, [[]])); // returns bool(true)
Ну, да … Просто используйте его со строгим набором в true . 😉