Php, in_array, 0 value
in_array is supposed to be used on indexed arrays ([0], [1], [2] etc), not with a dictionary as you have defined (key-value store).
If you want to check if your array $arr includes '0', try using the PHP function array_key_exists instead - http://php.net/manual/en/function.array-key-exists.php.
var_dump(array_key_exists(0, $arr));
Try adding a third parameter true
(strict mode) to your in_array
call.
This is a known issue, per the comments in the documentation. Consider the following examples:
in_array(0, array(42)); // FALSE
in_array(0, array('42')); // FALSE
in_array(0, array('Foo')); // TRUE
To avoid this, provide the third paramter, true
, placing the comparison in strict mode which will not only compare values, but types as well:
var_dump(in_array(0, $arr, true));
Other work-arounds exist that don't necessitate every check being placed in strict-mode:
in_array($value, $my_array, empty($value) && $value !== '0');
But Why?
The reason behind all of this is likely string-to-number conversions. If we attempt to get a number from "Bye", we are given 0
, which is the value we're asking to look-up.
echo intval("Bye"); // 0
To confirm this, we can use array_search
to find the key that is associated with the matching value:
$arr = array(2 => 'Bye', 52, 77, 3 => 'Hey');
echo array_search(0, $arr);
In this, the returned key is 2
, meaning 0
is being found in the conversion of Bye
to an integer.
This is a result of the loose comparison and type juggling.
Loose comparison means that PHP is using ==
not ===
when comparing elements. ==
does not compare that the two variable types are equal, only their value, while ===
will ensure that they match in type and value (e.g. compare 0 == FALSE
and 0 === FALSE
).
So, basically, your in_array function is checking:
0 == 'Bye'
0 == 'Hey'
0 == 77
Note that the 52 will get lost due to the way you created your array.
So, note that if you do:
print (0 == 'Bye');
You will get 1. Apparently, PHP is type juggling the 'Bye' to 0, which is the same thing that will happen when you cast a string to an int, e.g. (int) 'string'
will equal 0. Specific reference from the String conversion to numbers doc (Emphasis added):
The value is given by the initial portion of the string. If the string starts with valid numeric data, this will be the value used. Otherwise, the value will be 0 (zero). Valid numeric data is an optional sign, followed by one or more digits (optionally containing a decimal point), followed by an optional exponent. The exponent is an 'e' or 'E' followed by one or more digits.
Apparently, the integer type takes precedence over the string type (i.e. it could just as easily be doing the comparison by casting the int 0 to a string, which would then return False). This is specified in the comparison operators doc:
If you compare a number with a string or the comparison involves numerical strings, then each string is converted to a number and the comparison performed numerically.
Thanks for an interesting question that led me to do some research and learn something new!