Почему 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
. 😉