简体   繁体   中英

range() and in_array() behaviour, what am I doing wrong here?

This is the code , check output here -> http://codepad.org/7n7dM54e

<?php

$key = "a";
$array = range("0","7");
echo "array is : \n";
var_dump($array);
echo "key is : $key \n";
echo "in_array result \n";
var_dump(in_array($key,$array)); // why is it true, 'a' is not a "0" string or 0 int
echo "array_search result \n";
var_dump(array_search($key,$array)); // why is it index 0

?>

Solution

in_array() and array_search() support a type-safe check with the third parameter set to true . No conversion will be performed and the values will be compared as is, with type taken into account (like with the === operator).

So if you pass true at the end of each function call, you'll get the expected results:

// Both should return false
var_dump(in_array($key, $array, true));
var_dump(array_search($key, $array, true));

Why this is happening

Yep, it's definitely a type conversion, but not one that is specially implemented by in_array() or array_search() . It's nothing more than the loose comparison performed by the == operator.

Both methods call a C function called php_search_array() . This function is defined in /ext/standard/array.c . Here are some of the first few lines:

static void php_search_array(INTERNAL_FUNCTION_PARAMETERS, int behavior) /* {{{ */
{
    // ---------- snip ----------

    int (*is_equal_func)(zval *, zval *, zval * TSRMLS_DC) = is_equal_function;

    // ...

    if (strict) {
        is_equal_func = is_identical_function;
    }

    // ---------- snip ----------
}

If I'm not wrong, the is_equal_function you see there simply corresponds to (but may not actually be) the == operator, which does a very simple comparison regardless of data type. Type conversion may occur. (Likewise, is_identical_function corresponds to === .)

For example, '2abc' == 2 is true, but '2abc' == 3 is false. This is because comparing a string and an integer causes the string to be cast to integer before comparing. So casting the string '2abc' to an int returns 2.

So, like I said below, the same thing applies when you pass 'a' to both functions: it's being converted to an integer, resulting in 0 , which exists in the array returned by range() . And like I said, range() returns an array of integers (or floats) whether you pass integers or numeric strings as arguments.

From the manual entry on PHP's comparison operators :

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.


Old "Why is this happening"

I think the internal implementations of in_array() and array_search() by default try to convert the needle to be of the same type of the elements in the array being searched. If that is the case, since range() returns an array of integers, the string 'a' is converted to an integer, which is 0 and would thus return results for both function calls. Note that range() will produce an array of integers or floats even if you pass numbers as strings.

Well , this seems to be a bug with arrays that have a '0' in it

If you change $array = range("0","7"); to $array = range("1","7"); , you'll understand what I am trying to say

http://codepad.org/3099zpch

Also read the comment's in the php manual http://php.net/manual/en/function.in-array.php

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM