深入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_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内核(一), 相信大家通过本文多多少少都学到些知识吧,关于php内核知识继续关注本篇文章。 SAPI是Server Application Programming Interface(服务器应用编程接口)的缩写。PHP通过SAPI提供了一组接口,供应用和PHP内核之间进行数据交互。 简单的讲,就像函数的输入和输出一样,我们通过Linux命令行执行一段PHP代码,本质是Linux的Shell通过PHP的SAPI传入一组参数,Zend引擎执行后,返回给shell,由she
漏洞描述: Nginx默认是以CGI的方式支持PHP解析的,普遍的做法是在Nginx配置文件中通过正则匹配设置SCRIPT_FILENAME。当访问 http://192.168.1.102/phpinfo.jpg/1.php 这个URL时,$fastcgi_script_name会被设置为“phpinfo.jpg/1.php”,然后构造成SCRIPT_FILENAME传递给PHP CGI。如果PHP中开启了fix_pathinfo这个选项,PHP会认为SCRIPT_FILENAME是phpinfo.jp
SAPI: Server abstraction API,研究过PHP架构的同学应该知道这个东东的重要性,它提供了一个接口,使得PHP可以和其他应用进行交互数据。 本文不会详细介绍每个PHP的SAPI,只是针对最简单的CGI SAPI,来说明SAPI的机制。 首先,我们来看看PHP的架构图: 图1 PHP Architecture SAPI提供了一个和外部通信的接口, 对于PHP5.2,默认提供了很多种SAPI, 常见的给apache的mod_php5,CGI,给IIS的ISAPI,还有Shell的CLI
PHP提供了一个Embed SAPI,也就是说,PHP容许你在C/C++语言中调用PHP/ZE提供的函数。本文就通过基于Embed SAPI实现一个PHP的opcodes查看器。 首先,下载PHP源码以供编译, 我现在使用的是PHP5.3 alpha2 进入源码目录: ./configure --enable-embed --with-config-file-scan-dir=/etc/php.d --with-mysql --with-config-file-path=/etc/ ./make ./ma

深入理解PHP内核(一) - 2015-11-11 14:11:16

PHP作为一门简单而强大的语言,能够提供很多Web适用的语言特性。从实践出发,继弱类型变量原理探究后,本文继续带领大家深入理解php内核。 最近,和一个网友交流的时候,给我提了一个非常奇怪的问题。那就是,在一个运算中,加了一个引用之后,发现性能慢了一万倍。在我的脑海里面,引用是一个非常容易出错的问题,特别是PHP里面的引用,有非常多的陷阱。因为,以前专门研究过这一块PHP的源代码,所以,我可以比较清晰的解析引用到底是怎么一回事,希望,读了我这篇文章,能彻底理解这个问题。如果,有任何疑问,或者有一些你想了解
下面介绍10个免费、强大的PHP编辑器/开发工具。这些编辑器拥有调试器、增量执行PHP脚本、查看每一行的所有变量值等功能。 1) Notepad ++ Notepad++是一款非常有特色的编辑器,是开源软件,可以免费使用。支持的语言: C, C++, Java , C#, XML, HTML, PHP, Javascript! 功能有: 1. Notepad内置支持多达 27 种语法高亮度显示(囊括各种常见的源代码、脚本,值得一提的是,完美支持.nfo 文件查看),也支持自定义语言; 2. Notepad
先来个函数,是最近WordPress 3.6中刚刚引入的 /** * Add slashes to a string or array of strings. * * This should be used when preparing data for core API that expects slashed data. * This should not be used to escape data going directly into an SQL query. * * @since 3.6.0
文件列表。。文件内容。。 dbconn.php userListt.php editUser.php editDo.php detailUser.php deleteUser.php addUser.php addDo.php dbconn.php ?php// 创建数据库连接$con = mysql_connect("localhost",'root','') or die('error:'.mysql_error());mysql_select_db('hyxx',$con) or die('erro
用单引号代替双引号来包含字符串,这样做会更快一些。因为PHP会在双引号包围的字符串中搜寻变量,单引号则 不会,注意:只有echo能这么做,它是一种可以把多个字符串当作参数的“函数”(译注:PHP手册中说echo是语言结构,不是真正的函数,故把函数加 上了双引号)。 1、如果能将类的方法定义成static,就尽量定义成static,它的速度会提升将近4倍。 2、$row['id'] 的速度是$row[id]的7倍。 3、echo 比 print 快,并且使用echo的多重参数(译注:指用逗号而不是句点)代替
QQ 互联不允许 URL 有 Hash 存在,而 ShopNC 默认下是 ?act=toqqop=g 这样的链接回调的,所以会导致设置失败,或者 100010 错误。 1. 建立 /shop/api_qq.php 文件 2. 修改 /shop/api/qq/comm/config.php $_SESSION["callback"] = SHOP_SITE_URL."/api_qq.php"; 3. QQ 互联填写 http://域名/shop/api_qq.php shop/api_qq.php ?php