Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does in_array() return unexpected / strange results?

Why is in_array() sometimes behaving so strangely and returns such unexpected results?

Let's have a look at a few examples:

$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)

Huh? What's happening here!?

(Some years ago I wondered about this, at first, strange behaviour. I thought it might be useful for some people though, thus I entered this question.)

like image 402
Andreas Avatar asked May 06 '16 20:05

Andreas


People also ask

What is an In_array () function?

The in_array() function is an inbuilt function in PHP that is used to check whether a given value exists in an array or not. It returns TRUE if the given value is found in the given array, and FALSE otherwise.

Is In_array case sensitive?

The in_array() function searches an array for a specific value. Note: If the search parameter is a string and the type parameter is set to TRUE, the search is case-sensitive.


1 Answers

Solution (in short):

Use in_array() always with the third parameter 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)

So when you use in_array() with true as third parameter, the comparison between the searched value and the array is done strictly, meaning in_array() works like you would probably expect it.

(The parameter strict is also described in the php.net documentation.)

Explanation

Without the parameter strict set to true, the comparison between the searched value and each value of the array is done by equality and not by identity. This means that the value's type does not matter and thus PHP converts the values internally to the same data type in order to be able to compare them.

This means that in the first example, the searched value 'Gary' is converted to a boolean when it's compared with true, so it results in the comparison of true with true, which is obviously true.

The same goes with the second array, where 0 is finally compared with null, resulting in true, even though 0 is obviously not the same as null (this can be especially tricky when you work with numbers and / or function results for example, where null can express an empty value and not 0).

The third array then looks really weird, because we check for the value true in the array, which only contains -1, but in_array() still returns true for the comparison. In this case the -1 gets converted to a boolean true. So the problem is the same in both directions.

You can find more examples about the comparison problem in PHP (because this is the same as == / ===) in this Stack Overflow answer.

Unfortunately, the default for the strict parameter when calling in_array() is... well, yeah, false. :-/ PHP and it's typing...

Consequences

You should really never ever call in_array() without the strict parameter set to true. When you do not have arrays of mixed types and you only check the values with the same type, in_array() works as expected. See this example:

$arrayWithStrings = ['Andreas', 'Philipp', 'Friedrich'];
var_dump(in_array('Gary', $arrayWithStrings)); // returns bool(false)

So at least this works as expected. But in my opinion, it is much easier to just always call in_array() with strict true. (Similiar to the "SQL Injection Problem"... Just always use PDO and prepared statements so you're safe, even though it's a query without variable parameters. You're always safe then.)

Be careful though

You should definitely call in_array() with strict true. But there is one downside though, I do want to mention (even though it is obvious). You must definitely use the correct types when calling in_array() then:

$arrayWithNumbers = [1, 2, 3];
var_dump(in_array('1', $arrayWithNumbers, true)); // returns bool(false)

But you can just use Type Casting, when you know that you compare numbers:

$arrayWithNumbers = [1, 2, 3];
var_dump(in_array((int)'1', $arrayWithNumbers, true)); // returns bool(true)

Bonus

// Comparing false with an empty array
var_dump(in_array(false, [[]])); // returns bool(true)

Well, yeah... Just use it with strict set to true. ;-)

like image 110
Andreas Avatar answered Nov 15 '22 22:11

Andreas