深入php内核之php in array
先给大家介绍phpinarray函数基本知识热热身。
定义和用法
in_array()函数在数组中搜索给定的值。
语法
in_array(value,array,type)
说明
如果给定的值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@devtmp]#timephpb.php
real 0m9.517s
user 0m4.486s
sys 0m0.015s
竟然需要9s
in_array是这个样子的
boolin_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文件中
/*}}}*/ /*{{{protoboolin_array(mixedneedle,arrayhaystack[,boolstrict]) Checksifthegivenvalueexistsinthearray*/ PHP_FUNCTION(in_array) { php_search_array(INTERNAL_FUNCTION_PARAM_PASSTHRU,0); } /*}}}*/ /*{{{protomixedarray_search(mixedneedle,arrayhaystack[,boolstrict]) Searchesthearrayforagivenvalueandreturnsthecorrespondingkeyifsuccessful*/ PHP_FUNCTION(array_search) { php_search_array(INTERNAL_FUNCTION_PARAM_PASSTHRU,1); } /*}}}*/
顺便看到了array_search,原来和in_array的内部实现基本一致
其中函数的参数在./zend.h中
#defineINTERNAL_FUNCTION_PARAM_PASSTHRUht,return_value,return_value_ptr,this_ptr,return_value_usedTSRMLS_CC
第二步在ext/standard/array.c文件中查看php_search_array原型
/*voidphp_search_array(INTERNAL_FUNCTION_PARAMETERS,intbehavior) *0=returnboolean *1=returnkey */ staticvoidphp_search_array(INTERNAL_FUNCTION_PARAMETERS,intbehavior)/*{{{*/ { zval*value,/*valuetocheckfor*/ *array,/*arraytocheckin*/ **entry,/*pointertoarrayentry*/ res;/*comparisonresult*/ HashPositionpos;/*hashiterator*/ zend_boolstrict=0;/*strictcomparisonornot*/ ulongnum_key; uintstr_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,*entryTSRMLS_CC); if(Z_LVAL(res)){ if(behavior==0){ RETURN_TRUE; }else{ /*Returncurrentkey*/ switch(zend_hash_get_current_key_ex(Z_ARRVAL_P(array),&string_key,&str_key_len,&num_key,0,&pos)){ caseHASH_KEY_IS_STRING: RETURN_STRINGL(string_key,str_key_len-1,1); break; caseHASH_KEY_IS_LONG: RETURN_LONG(num_key); break; } } } zend_hash_move_forward_ex(Z_ARRVAL_P(array),&pos); } RETURN_FALSE; } /*}}}*/ /*{{{protoboolin_array(mixedneedle,arrayhaystack[,boolstrict]) Checksifthegivenvalueexistsinthearray*/
我们发现strict 这个值的不同有两种比较方式,看一下两个函数的不同之处
is_identical_function检查类型是否相同
ZEND_APIintis_identical_function(zval*result,zval*op1,zval*op2TSRMLS_DC)/*{{{*/ { Z_TYPE_P(result)=IS_BOOL; if(Z_TYPE_P(op1)!=Z_TYPE_P(op2)){ Z_LVAL_P(result)=0; returnSUCCESS; } switch(Z_TYPE_P(op1)){ caseIS_NULL: Z_LVAL_P(result)=1; break; caseIS_BOOL: caseIS_LONG: caseIS_RESOURCE: Z_LVAL_P(result)=(Z_LVAL_P(op1)==Z_LVAL_P(op2)); break; caseIS_DOUBLE: Z_LVAL_P(result)=(Z_DVAL_P(op1)==Z_DVAL_P(op2)); break; caseIS_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; caseIS_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,1TSRMLS_CC)==0); break; caseIS_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; returnFAILURE; } returnSUCCESS; } /*}}}*/
is_equal_function不检查类型是否相同,所以需要隐式转换
ZEND_APIintis_equal_function(zval*result,zval*op1,zval*op2TSRMLS_DC)/*{{{*/ { if(compare_function(result,op1,op2TSRMLS_CC)==FAILURE){ returnFAILURE; } ZVAL_BOOL(result,(Z_LVAL_P(result)==0)); returnSUCCESS; } /*}}}*/ ==》compare_function ZEND_APIintcompare_function(zval*result,zval*op1,zval*op2TSRMLS_DC)/*{{{*/ { intret; intconverted=0; zvalop1_copy,op2_copy; zval*op_free; while(1){ switch(TYPE_PAIR(Z_TYPE_P(op1),Z_TYPE_P(op2))){ caseTYPE_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)); returnSUCCESS; caseTYPE_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))); returnSUCCESS; caseTYPE_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))); returnSUCCESS; caseTYPE_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))); } returnSUCCESS; caseTYPE_PAIR(IS_ARRAY,IS_ARRAY): zend_compare_arrays(result,op1,op2TSRMLS_CC); returnSUCCESS; caseTYPE_PAIR(IS_NULL,IS_NULL): ZVAL_LONG(result,0); returnSUCCESS; caseTYPE_PAIR(IS_NULL,IS_BOOL): ZVAL_LONG(result,Z_LVAL_P(op2)?-1:0); returnSUCCESS; caseTYPE_PAIR(IS_BOOL,IS_NULL): ZVAL_LONG(result,Z_LVAL_P(op1)?1:0); returnSUCCESS; caseTYPE_PAIR(IS_BOOL,IS_BOOL): ZVAL_LONG(result,ZEND_NORMALIZE_BOOL(Z_LVAL_P(op1)-Z_LVAL_P(op2))); returnSUCCESS; caseTYPE_PAIR(IS_STRING,IS_STRING): zendi_smart_strcmp(result,op1,op2); returnSUCCESS; caseTYPE_PAIR(IS_NULL,IS_STRING): ZVAL_LONG(result,zend_binary_strcmp("",0,Z_STRVAL_P(op2),Z_STRLEN_P(op2))); returnSUCCESS; caseTYPE_PAIR(IS_STRING,IS_NULL): ZVAL_LONG(result,zend_binary_strcmp(Z_STRVAL_P(op1),Z_STRLEN_P(op1),"",0)); returnSUCCESS; caseTYPE_PAIR(IS_OBJECT,IS_NULL): ZVAL_LONG(result,1); returnSUCCESS; caseTYPE_PAIR(IS_NULL,IS_OBJECT): ZVAL_LONG(result,-1); returnSUCCESS; caseTYPE_PAIR(IS_OBJECT,IS_OBJECT): /*Ifbothareobjectssharingthesamecomparisionhandlerthenuseis*/ 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)){ /*objecthandlesareidentical,apparentlythisisthesameobject*/ ZVAL_LONG(result,0); returnSUCCESS; } ZVAL_LONG(result,Z_OBJ_HT_P(op1)->compare_objects(op1,op2TSRMLS_CC)); returnSUCCESS; } /*breakmissingintentionally*/ default: if(Z_TYPE_P(op1)==IS_OBJECT){ if(Z_OBJ_HT_P(op1)->get){ op_free=Z_OBJ_HT_P(op1)->get(op1TSRMLS_CC); ret=compare_function(result,op_free,op2TSRMLS_CC); zend_free_obj_get_result(op_freeTSRMLS_CC); returnret; }elseif(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_freeTSRMLS_CC); returnSUCCESS; } ret=compare_function(result,op_free,op2TSRMLS_CC); zend_free_obj_get_result(op_freeTSRMLS_CC); returnret; } } if(Z_TYPE_P(op2)==IS_OBJECT){ if(Z_OBJ_HT_P(op2)->get){ op_free=Z_OBJ_HT_P(op2)->get(op2TSRMLS_CC); ret=compare_function(result,op1,op_freeTSRMLS_CC); zend_free_obj_get_result(op_freeTSRMLS_CC); returnret; }elseif(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_freeTSRMLS_CC); returnSUCCESS; } ret=compare_function(result,op1,op_freeTSRMLS_CC); zend_free_obj_get_result(op_freeTSRMLS_CC); returnret; }elseif(Z_TYPE_P(op1)==IS_OBJECT){ ZVAL_LONG(result,1); returnSUCCESS; } } 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); returnSUCCESS; }elseif(Z_TYPE_P(op2)==IS_NULL){ zendi_convert_to_boolean(op1,op1_copy,result); ZVAL_LONG(result,Z_LVAL_P(op1)?1:0); returnSUCCESS; }elseif(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))); returnSUCCESS; }elseif(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))); returnSUCCESS; }else{ zendi_convert_scalar_to_number(op1,op1_copy,result); zendi_convert_scalar_to_number(op2,op2_copy,result); converted=1; } }elseif(Z_TYPE_P(op1)==IS_ARRAY){ ZVAL_LONG(result,1); returnSUCCESS; }elseif(Z_TYPE_P(op2)==IS_ARRAY){ ZVAL_LONG(result,-1); returnSUCCESS; }elseif(Z_TYPE_P(op1)==IS_OBJECT){ ZVAL_LONG(result,1); returnSUCCESS; }elseif(Z_TYPE_P(op2)==IS_OBJECT){ ZVAL_LONG(result,-1); returnSUCCESS; }else{ ZVAL_LONG(result,0); returnFAILURE; } } } } /*}}}*/