Welcome 微信登录

首页 / 网页编程 / PHP / 深入php内核之php in array

先给大家介绍php in array函数基本知识热热身。
定义和用法
in_array() 函数在数组中搜索给定的值。
语法
in_array(value,array,type)
参数描述
value必需。规定要在数组搜索的值。
array必需。规定要搜索的数组。
type可选。如果设置该参数为 true,则检查搜索的数据与数组的值的类型是否相同。

 说明

如果给定的值 value 存在于数组 array 中则返回 true。如果第三个参数设置为 true,函数只有在元素存在于数组中且数据类型与给定值相同时才返回 true。

如果没有在数组中找到参数,函数返回 false。
注释:如果 value 参数是字符串,且 type 参数设置为 true,则搜索区分大小写。
无意中看到一段代码
<?php$y="1800";$x = array();for($j=0;$j<50000;$j++){ $x[]= "{$j}";}for($i=0;$i<30000;$i++){ if(in_array($y,$x)){continue; } }
测试了一下
[root@dev tmp]# time php b.php
real    0m9.517s
user    0m4.486s
sys     0m0.015s
竟然需要9s
in_array是这个样子的
复制代码 代码如下:
bool in_array ( mixed $needle , array $haystack [, bool $strict = FALSE ] )

在 haystack 中搜索 needle,如果没有设置 strict 则使用宽松的比较。
needle
待搜索的值。如果 needle 是字符串,则比较是区分大小写的。
haystack
这个数组。
strict
如果第三个参数 strict 的值为 TRUE 则 in_array() 函数还会检查 needle 的类型是否和 haystack 中的相同。
那么我看一下源代码
第一步 在ext/standard/array.c 文件中
/* }}} *//* {{{ proto bool in_array(mixed needle, array haystack [, bool strict]) Checks if the given value exists in the array */ PHP_FUNCTION(in_array){ php_search_array(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); }/* }}} */ /* {{{ proto mixed array_search(mixed needle, array haystack [, bool strict]) Searches the array for a given value and returns the corresponding key if successful */PHP_FUNCTION(array_search) { php_search_array(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); }/* }}} */ 
顺便看到了array_search,原来和in_array的内部实现基本一致
其中函数的参数 在./zend.h中
#define INTERNAL_FUNCTION_PARAM_PASSTHRU ht, return_value, return_value_ptr, this_ptr, return_value_used TSRMLS_CC
第二步 在ext/standard/array.c 文件中 查看php_search_array原型
/* void php_search_array(INTERNAL_FUNCTION_PARAMETERS, int behavior) * 0 = return boolean * 1 = return key */static 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 */ res;/* comparison result */ HashPosition pos;/* hash iterator */ zend_bool strict = 0;/* strict comparison or not */ ulong num_key; uint str_key_len; char *string_key; int (*is_equal_func)(zval *, zval *, zval * TSRMLS_DC) = is_equal_function; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "za|b", &value, &array, &strict) == FAILURE) {return; }if (strict) {is_equal_func = is_identical_function; }zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(array), &pos); while (zend_hash_get_current_data_ex(Z_ARRVAL_P(array), (void **)&entry, &pos) == SUCCESS) {is_equal_func(&res, value, *entry TSRMLS_CC);if (Z_LVAL(res)) { if (behavior == 0) {RETURN_TRUE; } else {/* Return current key */switch (zend_hash_get_current_key_ex(Z_ARRVAL_P(array), &string_key, &str_key_len, &num_key, 0, &pos)) { case HASH_KEY_IS_STRING:RETURN_STRINGL(string_key, str_key_len - 1, 1);break; case HASH_KEY_IS_LONG:RETURN_LONG(num_key);break;} }}zend_hash_move_forward_ex(Z_ARRVAL_P(array), &pos); }RETURN_FALSE;}/* }}} *//* {{{ proto bool in_array(mixed needle, array haystack [, bool strict]) Checks if the given value exists in the array */
我们发现 strict  这个值的不同有两种比较方式,看一下两个函数的不同之处
is_identical_function 检查类型是否相同
ZEND_API int is_identical_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */{ Z_TYPE_P(result) = IS_BOOL; if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) {Z_LVAL_P(result) = 0;return SUCCESS; }switch (Z_TYPE_P(op1)) {case IS_NULL: Z_LVAL_P(result) = 1; break;case IS_BOOL:case IS_LONG:case IS_RESOURCE: Z_LVAL_P(result) = (Z_LVAL_P(op1) == Z_LVAL_P(op2)); break;case IS_DOUBLE: Z_LVAL_P(result) = (Z_DVAL_P(op1) == Z_DVAL_P(op2)); break;case IS_STRING: Z_LVAL_P(result) = ((Z_STRLEN_P(op1) == Z_STRLEN_P(op2)) && (!memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1)))); break;case IS_ARRAY: Z_LVAL_P(result) = (Z_ARRVAL_P(op1) == Z_ARRVAL_P(op2) zend_hash_compare(Z_ARRVAL_P(op1), Z_ARRVAL_P(op2), (compare_func_t) hash_zval_identical_function, 1 TSRMLS_CC)==0); break;case IS_OBJECT: if (Z_OBJ_HT_P(op1) == Z_OBJ_HT_P(op2)) { Z_LVAL_P(result) = (Z_OBJ_HANDLE_P(op1) == Z_OBJ_HANDLE_P(op2)); } else { Z_LVAL_P(result) = 0; } break;default: Z_LVAL_P(result) = 0; return FAILURE; }return SUCCESS;}/* }}} */
is_equal_function 不检查类型是否相同,所以需要隐式转换

ZEND_API int is_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */{ if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) {return FAILURE; }ZVAL_BOOL(result, (Z_LVAL_P(result) == 0)); return SUCCESS;}/* }}} */==》compare_functionZEND_API int compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */{int ret; int converted = 0; zval op1_copy, op2_copy; zval *op_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): zend_compare_arrays(result, op1, op2 TSRMLS_CC); return SUCCESS; case TYPE_PAIR(IS_NULL, IS_NULL): ZVAL_LONG(result, 0); return SUCCESS; case TYPE_PAIR(IS_NULL, IS_BOOL): ZVAL_LONG(result, Z_LVAL_P(op2) ? -1 : 0); return SUCCESS; case TYPE_PAIR(IS_BOOL, IS_NULL): ZVAL_LONG(result, Z_LVAL_P(op1) ? 1 : 0); return SUCCESS; case TYPE_PAIR(IS_BOOL, IS_BOOL): ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(op1) - Z_LVAL_P(op2))); return SUCCESS; case TYPE_PAIR(IS_STRING, IS_STRING): zendi_smart_strcmp(result, op1, op2); return SUCCESS; case TYPE_PAIR(IS_NULL, IS_STRING): ZVAL_LONG(result, zend_binary_strcmp("", 0, Z_STRVAL_P(op2), Z_STRLEN_P(op2))); return SUCCESS; case TYPE_PAIR(IS_STRING, IS_NULL): ZVAL_LONG(result, zend_binary_strcmp(Z_STRVAL_P(op1), Z_STRLEN_P(op1), "", 0)); 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; case TYPE_PAIR(IS_OBJECT, IS_OBJECT): /* If both are objects sharing the same comparision handler then use is */ if (Z_OBJ_HANDLER_P(op1,compare_objects) == Z_OBJ_HANDLER_P(op2,compare_objects)) {if (Z_OBJ_HANDLE_P(op1) == Z_OBJ_HANDLE_P(op2)) { /* object handles are identical, apparently this is the same object */ ZVAL_LONG(result, 0); return SUCCESS;}ZVAL_LONG(result, Z_OBJ_HT_P(op1)->compare_objects(op1, op2 TSRMLS_CC));return SUCCESS; } /* break missing intentionally */ default: if (Z_TYPE_P(op1) == IS_OBJECT) {if (Z_OBJ_HT_P(op1)->get) { op_free = Z_OBJ_HT_P(op1)->get(op1 TSRMLS_CC); ret = compare_function(result, op_free, op2 TSRMLS_CC); zend_free_obj_get_result(op_free TSRMLS_CC); return ret;} else if (Z_TYPE_P(op2) != IS_OBJECT && Z_OBJ_HT_P(op1)->cast_object) { ALLOC_INIT_ZVAL(op_free); if (Z_OBJ_HT_P(op1)->cast_object(op1, op_free, Z_TYPE_P(op2) TSRMLS_CC) == FAILURE) {ZVAL_LONG(result, 1);zend_free_obj_get_result(op_free TSRMLS_CC);return SUCCESS; } ret = compare_function(result, op_free, op2 TSRMLS_CC); zend_free_obj_get_result(op_free TSRMLS_CC); return ret;} } if (Z_TYPE_P(op2) == IS_OBJECT) {if (Z_OBJ_HT_P(op2)->get) { op_free = Z_OBJ_HT_P(op2)->get(op2 TSRMLS_CC); ret = compare_function(result, op1, op_free TSRMLS_CC); zend_free_obj_get_result(op_free TSRMLS_CC); return ret;} else if (Z_TYPE_P(op1) != IS_OBJECT && Z_OBJ_HT_P(op2)->cast_object) { ALLOC_INIT_ZVAL(op_free); if (Z_OBJ_HT_P(op2)->cast_object(op2, op_free, Z_TYPE_P(op1) TSRMLS_CC) == FAILURE) {ZVAL_LONG(result, -1);zend_free_obj_get_result(op_free TSRMLS_CC);return SUCCESS; } ret = compare_function(result, op1, op_free TSRMLS_CC); zend_free_obj_get_result(op_free TSRMLS_CC); return ret;} else if (Z_TYPE_P(op1) == IS_OBJECT) { ZVAL_LONG(result, 1); return SUCCESS;} } if (!converted) {if (Z_TYPE_P(op1) == IS_NULL) { zendi_convert_to_boolean(op2, op2_copy, result); ZVAL_LONG(result, Z_LVAL_P(op2) ? -1 : 0); return SUCCESS;} else if (Z_TYPE_P(op2) == IS_NULL) { zendi_convert_to_boolean(op1, op1_copy, result); ZVAL_LONG(result, Z_LVAL_P(op1) ? 1 : 0); return SUCCESS;} else if (Z_TYPE_P(op1) == IS_BOOL) { zendi_convert_to_boolean(op2, op2_copy, result); ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(op1) - Z_LVAL_P(op2))); return SUCCESS;} else if (Z_TYPE_P(op2) == IS_BOOL) { zendi_convert_to_boolean(op1, op1_copy, result); ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_LVAL_P(op1) - Z_LVAL_P(op2))); return SUCCESS;} else { zendi_convert_scalar_to_number(op1, op1_copy, result); zendi_convert_scalar_to_number(op2, op2_copy, result); 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 if (Z_TYPE_P(op1)==IS_OBJECT) {ZVAL_LONG(result, 1);return SUCCESS; } else if (Z_TYPE_P(op2)==IS_OBJECT) {ZVAL_LONG(result, -1);return SUCCESS; } else {ZVAL_LONG(result, 0);return FAILURE; }}}} /* }}} */