深入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;
}
}
}
}
/*}}}*/