Почему in_array () возвращает неожиданные / странные результаты?

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