当前位置: 代码迷 >> 综合 >> PHP的一个坑--in_array
  详细解决方案

PHP的一个坑--in_array

热度:89   发布时间:2024-01-03 23:01:47.0

今天在找问题的时候发现了一个小坑。
in_array定义:

in_array ( mixed $needle , array $haystack [, bool $strict = FALSE ] ) : bool着重说一下第三个参数。
strict
如果第三个参数 strict 的值为 TRUE 则 in_array() 函数还会检查 needle 的类型是否和 haystack 中的相同。

看一组代码

$a = in_array(0, ['a', 'b']);
$b = in_array(null, ['a', 'b']);
$c = in_array(false, ['a', 'b']);
$d = in_array('', ['a', 'b']);$a1 = in_array(0, ['a', 'b'],true);
$b1 = in_array(null, ['a', 'b'],true);
$c1 = in_array(false, ['a', 'b'],true);
$d1 = in_array('', ['a', 'b'],true);$e = in_array(0, [0]);
$f = in_array(null, [0]);
$g = in_array(false, [0]);
$h = in_array('', [0]);$e1 = in_array(0, [0],TRUE);
$f1 = in_array(null, [0],true);
$g1 = in_array(false, [0],true);
$h1 = in_array('', [0],true);

你们觉得输出都会输出什么。可以先自己判断一下。

a--true
b--false
c--false
d--falsea1--false
b1--false
c1--false
d1--falsee--true
f--true
g--true
h--truee1--true
f1--false
g1--false
h1--false

注意改变$strict而导致返回结果不同的代码。

没有强调类型前 $strict = false 强调类型后 $strict = true
$a = in_array(0, [‘a’, ‘b’]); $a1 = in_array(0, [‘a’, ‘b’],true);
$f = in_array(null, [0]); $f1 = in_array(null, [0],true);
$g = in_array(false, [0]); $g1 = in_array(false, [0],true);
$h = in_array(’’, [0]); $h1 = in_array(’’, [0],true);
true false

看一下PHP中in_array源码
用第一个分析。->$a = in_array(0, [‘a’, ‘b’]);

php-src/ext/standard/array.c
in_array和array_search内部实现是一样的。
在这里插入图片描述
其中INTERNAL_FUNCTION_PARAM_PASSTHRU

#define INTERNAL_FUNCTION_PARAM_PASSTHRU ht, return_value, return_value_ptr, this_ptr, return_value_used TSRMLS_CC
/* void php_search_array(INTERNAL_FUNCTION_PARAMETERS, int behavior)* 0 = return boolean* 1 = return key*/
static inline void php_search_array(INTERNAL_FUNCTION_PARAMETERS, int behavior) /* {
   {
   { */
{zval *value,				/* value to check for */*array,				/* array to check in */*entry;				/* pointer to array entry */zend_ulong num_idx;zend_string *str_idx;zend_bool strict = 0;		/* strict comparison or not */ZEND_PARSE_PARAMETERS_START(2, 3)Z_PARAM_ZVAL(value)Z_PARAM_ARRAY(array)Z_PARAM_OPTIONALZ_PARAM_BOOL(strict)ZEND_PARSE_PARAMETERS_END();if (strict) {ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_idx, str_idx, entry) {ZVAL_DEREF(entry);if (fast_is_identical_function(value, entry)) {if (behavior == 0) {RETURN_TRUE;} else {if (str_idx) {RETVAL_STR_COPY(str_idx);} else {RETVAL_LONG(num_idx);}return;}}} ZEND_HASH_FOREACH_END();} else {if (Z_TYPE_P(value) == IS_LONG) {ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_idx, str_idx, entry) {if (fast_equal_check_long(value, entry)) {if (behavior == 0) {RETURN_TRUE;} else {if (str_idx) {RETVAL_STR_COPY(str_idx);} else {RETVAL_LONG(num_idx);}return;}}} ZEND_HASH_FOREACH_END();} else if (Z_TYPE_P(value) == IS_STRING) {ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_idx, str_idx, entry) {if (fast_equal_check_string(value, entry)) {if (behavior == 0) {RETURN_TRUE;} else {if (str_idx) {RETVAL_STR_COPY(str_idx);} else {RETVAL_LONG(num_idx);}return;}}} ZEND_HASH_FOREACH_END();} else {ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_idx, str_idx, entry) {if (fast_equal_check_function(value, entry)) {if (behavior == 0) {RETURN_TRUE;} else {if (str_idx) {RETVAL_STR_COPY(str_idx);} else {RETVAL_LONG(num_idx);}return;}}} ZEND_HASH_FOREACH_END();}}RETURN_FALSE;
}

当$a = in_array(0, [‘a’, ‘b’]),进入fast_equal_check_long

static zend_always_inline int fast_equal_check_function(zval *op1, zval *op2)
{zval result;if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) {if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {return Z_LVAL_P(op1) == Z_LVAL_P(op2);} else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) {return ((double)Z_LVAL_P(op1)) == Z_DVAL_P(op2);}} else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) {if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) {return Z_DVAL_P(op1) == Z_DVAL_P(op2);} else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {return Z_DVAL_P(op1) == ((double)Z_LVAL_P(op2));}} else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) {if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) {return zend_fast_equal_strings(Z_STR_P(op1), Z_STR_P(op2));}}compare_function(&result, op1, op2);return Z_LVAL(result) == 0;
}

这里因为Z_TYPE_P(op2) != IS_LONG 会进入compare_function中。

ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) /* {
   {
   { */
{int ret;int converted = 0;zval op1_copy, op2_copy;zval *op_free, tmp_free;while (1) {switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {case TYPE_PAIR(IS_LONG, IS_LONG):ZVAL_LONG(result, Z_LVAL_P(op1)>Z_LVAL_P(op2)?1:(Z_LVAL_P(op1)<Z_LVAL_P(op2)?-1:0));return SUCCESS;case TYPE_PAIR(IS_DOUBLE, IS_LONG):Z_DVAL_P(result) = Z_DVAL_P(op1) - (double)Z_LVAL_P(op2);ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));return SUCCESS;case TYPE_PAIR(IS_LONG, IS_DOUBLE):Z_DVAL_P(result) = (double)Z_LVAL_P(op1) - Z_DVAL_P(op2);ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));return SUCCESS;case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):if (Z_DVAL_P(op1) == Z_DVAL_P(op2)) {ZVAL_LONG(result, 0);} else {Z_DVAL_P(result) = Z_DVAL_P(op1) - Z_DVAL_P(op2);ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));}return SUCCESS;case TYPE_PAIR(IS_ARRAY, IS_ARRAY):ZVAL_LONG(result, zend_compare_arrays(op1, op2));return SUCCESS;case TYPE_PAIR(IS_NULL, IS_NULL):case TYPE_PAIR(IS_NULL, IS_FALSE):case TYPE_PAIR(IS_FALSE, IS_NULL):case TYPE_PAIR(IS_FALSE, IS_FALSE):case TYPE_PAIR(IS_TRUE, IS_TRUE):ZVAL_LONG(result, 0);return SUCCESS;case TYPE_PAIR(IS_NULL, IS_TRUE):ZVAL_LONG(result, -1);return SUCCESS;case TYPE_PAIR(IS_TRUE, IS_NULL):ZVAL_LONG(result, 1);return SUCCESS;case TYPE_PAIR(IS_STRING, IS_STRING):if (Z_STR_P(op1) == Z_STR_P(op2)) {ZVAL_LONG(result, 0);return SUCCESS;}ZVAL_LONG(result, zendi_smart_strcmp(Z_STR_P(op1), Z_STR_P(op2)));return SUCCESS;case TYPE_PAIR(IS_NULL, IS_STRING):ZVAL_LONG(result, Z_STRLEN_P(op2) == 0 ? 0 : -1);return SUCCESS;case TYPE_PAIR(IS_STRING, IS_NULL):ZVAL_LONG(result, Z_STRLEN_P(op1) == 0 ? 0 : 1);return SUCCESS;case TYPE_PAIR(IS_OBJECT, IS_NULL):ZVAL_LONG(result, 1);return SUCCESS;case TYPE_PAIR(IS_NULL, IS_OBJECT):ZVAL_LONG(result, -1);return SUCCESS;default:if (Z_ISREF_P(op1)) {op1 = Z_REFVAL_P(op1);continue;} else if (Z_ISREF_P(op2)) {op2 = Z_REFVAL_P(op2);continue;}if (Z_TYPE_P(op1) == IS_OBJECT && Z_OBJ_HANDLER_P(op1, compare)) {ret = Z_OBJ_HANDLER_P(op1, compare)(result, op1, op2);if (UNEXPECTED(Z_TYPE_P(result) != IS_LONG)) {convert_compare_result_to_long(result);}return ret;} else if (Z_TYPE_P(op2) == IS_OBJECT && Z_OBJ_HANDLER_P(op2, compare)) {ret = Z_OBJ_HANDLER_P(op2, compare)(result, op1, op2);if (UNEXPECTED(Z_TYPE_P(result) != IS_LONG)) {convert_compare_result_to_long(result);}return ret;}if (Z_TYPE_P(op1) == IS_OBJECT && Z_TYPE_P(op2) == IS_OBJECT) {if (Z_OBJ_P(op1) == Z_OBJ_P(op2)) {/* object handles are identical, apparently this is the same object */ZVAL_LONG(result, 0);return SUCCESS;}if (Z_OBJ_HANDLER_P(op1, compare_objects) == Z_OBJ_HANDLER_P(op2, compare_objects)) {ZVAL_LONG(result, Z_OBJ_HANDLER_P(op1, compare_objects)(op1, op2));return SUCCESS;}}if (Z_TYPE_P(op1) == IS_OBJECT) {if (Z_OBJ_HT_P(op1)->get) {zval rv;op_free = Z_OBJ_HT_P(op1)->get(Z_OBJ_P(op1), &rv);ret = compare_function(result, op_free, op2);zend_free_obj_get_result(op_free);return ret;} else if (Z_TYPE_P(op2) != IS_OBJECT && Z_OBJ_HT_P(op1)->cast_object) {ZVAL_UNDEF(&tmp_free);if (Z_OBJ_HT_P(op1)->cast_object(Z_OBJ_P(op1), &tmp_free, ((Z_TYPE_P(op2) == IS_FALSE || Z_TYPE_P(op2) == IS_TRUE) ? _IS_BOOL : Z_TYPE_P(op2))) == FAILURE) {ZVAL_LONG(result, 1);zend_free_obj_get_result(&tmp_free);return SUCCESS;}ret = compare_function(result, &tmp_free, op2);zend_free_obj_get_result(&tmp_free);return ret;}}if (Z_TYPE_P(op2) == IS_OBJECT) {if (Z_OBJ_HT_P(op2)->get) {zval rv;op_free = Z_OBJ_HT_P(op2)->get(Z_OBJ_P(op2), &rv);ret = compare_function(result, op1, op_free);zend_free_obj_get_result(op_free);return ret;} else if (Z_TYPE_P(op1) != IS_OBJECT && Z_OBJ_HT_P(op2)->cast_object) {ZVAL_UNDEF(&tmp_free);if (Z_OBJ_HT_P(op2)->cast_object(Z_OBJ_P(op2), &tmp_free, ((Z_TYPE_P(op1) == IS_FALSE || Z_TYPE_P(op1) == IS_TRUE) ? _IS_BOOL : Z_TYPE_P(op1))) == FAILURE) {ZVAL_LONG(result, -1);zend_free_obj_get_result(&tmp_free);return SUCCESS;}ret = compare_function(result, op1, &tmp_free);zend_free_obj_get_result(&tmp_free);return ret;} else if (Z_TYPE_P(op1) == IS_OBJECT) {ZVAL_LONG(result, 1);return SUCCESS;}}if (!converted) {if (Z_TYPE_P(op1) < IS_TRUE) {ZVAL_LONG(result, zval_is_true(op2) ? -1 : 0);return SUCCESS;} else if (Z_TYPE_P(op1) == IS_TRUE) {ZVAL_LONG(result, zval_is_true(op2) ? 0 : 1);return SUCCESS;} else if (Z_TYPE_P(op2) < IS_TRUE) {ZVAL_LONG(result, zval_is_true(op1) ? 1 : 0);return SUCCESS;} else if (Z_TYPE_P(op2) == IS_TRUE) {ZVAL_LONG(result, zval_is_true(op1) ? 0 : -1);return SUCCESS;} else {op1 = zendi_convert_scalar_to_number(op1, &op1_copy, result, 1);op2 = zendi_convert_scalar_to_number(op2, &op2_copy, result, 1);if (EG(exception)) {if (result != op1) {ZVAL_UNDEF(result);}return FAILURE;}converted = 1;}} else if (Z_TYPE_P(op1)==IS_ARRAY) {ZVAL_LONG(result, 1);return SUCCESS;} else if (Z_TYPE_P(op2)==IS_ARRAY) {ZVAL_LONG(result, -1);return SUCCESS;} else {ZEND_ASSERT(0);zend_throw_error(NULL, "Unsupported operand types");if (result != op1) {ZVAL_UNDEF(result);}return FAILURE;}}}
}

ZVAL_LONG相当于把-1给result。
进入default
在这里插入图片描述
取op1=0,op2=a。
op1 < IS_TRUE,op2也不是true。result返回0。

那么在fast_equal_check_long中返回1。

再退出至php_search_array中。又因为(strict)behavior=0,所以返回true。所以$a = in_array(0, [‘a’, ‘b’]);返回true。

至于加了true之后的,php_search_array中behavior变为1,返回false。

之后的几个可以自己看源码分析一下。