找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 1163|回复: 0
打印 上一主题 下一主题

深入php内核之php in array

[复制链接]

2617

主题

2617

帖子

7789

积分

论坛元老

Rank: 8Rank: 8

积分
7789
跳转到指定楼层
楼主
发表于 2018-2-14 05:41:42 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

            先给大家介绍php in array函数基本知识热热身。
定义和用法
in_array() 函数在数组中搜索给定的值。
语法
in_array(value,array,type)

      参数
      描述
   
   
      value
      必需。规定要在数组搜索的值。
   
   
      array
      必需。规定要搜索的数组。
   
   
      type
      可选。如果设置该参数为 true,则检查搜索的数据与数组的值的类型是否相同。
   
说明
如果给定的值 value 存在于数组 array 中则返回 true。如果第三个参数设置为 true,函数只有在元素存在于数组中且数据类型与给定值相同时才返回 true。
如果没有在数组中找到参数,函数返回 false。
注释:如果 value 参数是字符串,且 type 参数设置为 true,则搜索区分大小写。
无意中看到一段代码
测试了一下
[root@dev tmp]# time php b.php
real    0m9.517s
user    0m4.486s
sys     0m0.015s
竟然需要9s
in_array是这个样子的
[U]复制代码[/U] 代码如下:
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_function
ZEND_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)?1Z_LVAL_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;
   }
  }
}  
}   
/* }}} */
            
            
您可能感兴趣的文章:
  • php natsort内核函数浅析
  • php in_array 函数使用说明与in_array需要注意的地方说明
  • PHP数组的交集array_intersect(),array_intersect_assoc(),array_inter_key()函数的小问题
  • php array_intersect比array_diff快(附详细的使用说明)
  • PHP内核介绍及扩展开发指南—基础知识
  • php数组函数序列之in_array() 查找数组值是否存在
  • php数组函数序列之array_combine() - 数组合并函数使用说明
  • php数组函数序列之in_array() - 查找数组中是否存在指定值
  • php数组函数序列之array_intersect() 返回两个或多个数组的交集数组
  • 使用js判断数组中是否包含某一元素(类似于php中的in_array())
  • PHP内核探索:变量存储与类型使用说明
  • PHP内核探索:变量概述
  • php内核解析:PHP中的哈希表
  • 2个自定义的PHP in_array 函数,解决大量数据判断in_array的效率问题
  • php数组查找函数in_array()、array_search()、array_key_exists()使用实例
  • PHP函数in_array()使用详解
  • php提示Warning:mysql_fetch_array() expects的解决方法
  • PHP内核探索:哈希表碰撞攻击原理
  • 深入理解PHP内核(一)
  • 深入理解PHP内核(二)之SAPI探究
            
  • 分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
    收藏收藏
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    用户反馈
    客户端