0

0

深入PHP内核之in_array

php中文网

php中文网

发布时间:2016-07-29 09:12:14

|

1103人浏览过

|

来源于php中文网

原创

无意中看到一段代码

<?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

立即学习PHP免费学习笔记(深入)”;

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 文件中

远航CMS(yhcms)(分站版)2.6.5
远航CMS(yhcms)(分站版)2.6.5

远航CMS(yhcms)是一套基于PHP+MYSQL为核心开发的专业营销型企业建站系统。是国内首家免费+开源自带分站系统的php内容管理系统。长期以来不断的完善、创新,远航CMS会为您带来全新的体验!产品十大优势:模板分离:模板程序分离,深度二次开发三网合一:电脑/手机/微信 多终端访问自定义广告:图片/文字/动画定时发布:SEO维护,无需人工值守多词生成:栏目关键词多方案生成SEO设置:自定义U

下载

/* }}} */                                                      
                                                               
/* {{{ 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)?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;
            }
      }     
   }         
}             
/* }}} */ 

以上就介绍了深入PHP内核之in_array,包括了方面的内容,希望对PHP教程有兴趣的朋友有所帮助。

相关文章

PHP速学教程(入门到精通)
PHP速学教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法
pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法

本专题系统整理pixiv网页版官网入口及登录访问方式,涵盖官网登录页面直达路径、在线阅读入口及快速进入方法说明,帮助用户高效找到pixiv官方网站,实现便捷、安全的网页端浏览与账号登录体验。

616

2026.02.13

微博网页版主页入口与登录指南_官方网页端快速访问方法
微博网页版主页入口与登录指南_官方网页端快速访问方法

本专题系统整理微博网页版官方入口及网页端登录方式,涵盖首页直达地址、账号登录流程与常见访问问题说明,帮助用户快速找到微博官网主页,实现便捷、安全的网页端登录与内容浏览体验。

194

2026.02.13

Flutter跨平台开发与状态管理实战
Flutter跨平台开发与状态管理实战

本专题围绕Flutter框架展开,系统讲解跨平台UI构建原理与状态管理方案。内容涵盖Widget生命周期、路由管理、Provider与Bloc状态管理模式、网络请求封装及性能优化技巧。通过实战项目演示,帮助开发者构建流畅、可维护的跨平台移动应用。

91

2026.02.13

TypeScript工程化开发与Vite构建优化实践
TypeScript工程化开发与Vite构建优化实践

本专题面向前端开发者,深入讲解 TypeScript 类型系统与大型项目结构设计方法,并结合 Vite 构建工具优化前端工程化流程。内容包括模块化设计、类型声明管理、代码分割、热更新原理以及构建性能调优。通过完整项目示例,帮助开发者提升代码可维护性与开发效率。

20

2026.02.13

Redis高可用架构与分布式缓存实战
Redis高可用架构与分布式缓存实战

本专题围绕 Redis 在高并发系统中的应用展开,系统讲解主从复制、哨兵机制、Cluster 集群模式及数据分片原理。内容涵盖缓存穿透与雪崩解决方案、分布式锁实现、热点数据优化及持久化策略。通过真实业务场景演示,帮助开发者构建高可用、可扩展的分布式缓存系统。

54

2026.02.13

c语言 数据类型
c语言 数据类型

本专题整合了c语言数据类型相关内容,阅读专题下面的文章了解更多详细内容。

29

2026.02.12

雨课堂网页版登录入口与使用指南_官方在线教学平台访问方法
雨课堂网页版登录入口与使用指南_官方在线教学平台访问方法

本专题系统整理雨课堂网页版官方入口及在线登录方式,涵盖账号登录流程、官方直连入口及平台访问方法说明,帮助师生用户快速进入雨课堂在线教学平台,实现便捷、高效的课程学习与教学管理体验。

15

2026.02.12

豆包AI网页版入口与智能创作指南_官方在线写作与图片生成使用方法
豆包AI网页版入口与智能创作指南_官方在线写作与图片生成使用方法

本专题汇总豆包AI官方网页版入口及在线使用方式,涵盖智能写作工具、图片生成体验入口和官网登录方法,帮助用户快速直达豆包AI平台,高效完成文本创作与AI生图任务,实现便捷智能创作体验。

598

2026.02.12

PostgreSQL性能优化与索引调优实战
PostgreSQL性能优化与索引调优实战

本专题面向后端开发与数据库工程师,深入讲解 PostgreSQL 查询优化原理与索引机制。内容包括执行计划分析、常见索引类型对比、慢查询优化策略、事务隔离级别以及高并发场景下的性能调优技巧。通过实战案例解析,帮助开发者提升数据库响应速度与系统稳定性。

56

2026.02.12

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PHP函数之array数组函数视频讲解
PHP函数之array数组函数视频讲解

共76课时 | 26.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号