PHP源代码数组统计count分析


Posted in PHP onAugust 02, 2011

zend给php的所有变量都用结构的方式去保存,而字符串的保存和数组的保存也是不同的,数组采用的是hash表的方式去保存(大家知道hash保存的地址有效的减少冲突-hash散列表的概念你懂的),而在php中的结构体上表现如下:

//文件1:zend/zend.h 
/* 
* zval 
*/ 
typedef struct _zval_struct zval; 
... 
typedef union _zvalue_value { 
long lval; /* long value */ 
double dval; /* double value */ 
struct { 
char *val; 
int len; 
} str; 
HashTable *ht; /* hash table value */ 
zend_object_value obj; 
} zvalue_value; struct _zval_struct { 
/* Variable information */ 
zvalue_value value; /* value */ 
zend_uint refcount__gc; 
zend_uchar type; /* active type */ 
zend_uchar is_ref__gc; 
}; 
//hash表的结构如下 
//文件2:zend/zend_hash.h 
typedef struct _hashtable { 
uint nTableSize; 
uint nTableMask; 
uint nNumOfElements; 
ulong nNextFreeElement; 
Bucket *pInternalPointer; /* Used for element traversal */ 
Bucket *pListHead; 
Bucket *pListTail; 
Bucket **arBuckets; 
dtor_func_t pDestructor; 
zend_bool persistent; 
unsigned char nApplyCount; 
zend_bool bApplyProtection; 
#if ZEND_DEBUG 
int inconsistent; 
#endif 
} 
HashTable;

一般的变量(字符串)在使用strlen获取长度的时候,其实获取的就是zvalue_value.str这个结构中的len属性,效率上O(1)次,特别说明的一点是:strlen在php中并没有核心的实现,而是在使用了zend中的宏定义来获取:
//文件3:zend/zend_operators.php 
#define Z_STRLEN(zval) (zval).value.str.len 
... 
#define Z_STRLEN_P(zval_p) Z_STRLEN(*zval_p) 
... 
#define Z_STRLEN_PP(zval_pp) Z_STRLEN(**zval_pp)

而对于数组的count操作,其实有两种结果,在count 的api中也提到了第二个参数mode《http://www.php.net/manual/en/function.count.php》,这个mode参数指明了,是否需要重新统计,而它的重新统计将会遍历一次数组,效率上是O(N)[N:长度],默认情况下是不重新统计,那这个时候将会直接输出hashtable中的nNumOfElements,此时的效率也是O(1)次:count代码如下:
//文件4:ext/standard/array.c 
PHP_FUNCTION(count) 
{ 
zval *array; 
long mode = COUNT_NORMAL; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &array, &mode) == FAILURE) { 
return; 
} 
switch (Z_TYPE_P(array)) { 
case IS_NULL: 
RETURN_LONG(0); 
break; 
case IS_ARRAY: 
RETURN_LONG (php_count_recursive (array, mode TSRMLS_CC)); 
break; 
..... 
//php_count_recursive的实现 
static int php_count_recursive(zval *array, long mode TSRMLS_DC) /* {{{ */ 
{ 
long cnt = 0; 
zval **element; 
if (Z_TYPE_P(array) == IS_ARRAY) { 
//错误处理 
if (Z_ARRVAL_P(array)->nApplyCount > 1) { 
php_error_docref(NULL TSRMLS_CC, E_WARNING, "recursion detected"); 
return 0; 
} 
//通过zend_hash_num_elements直接获得长度 
cnt = zend_hash_num_elements(Z_ARRVAL_P(array)); 
//如果指定了需要重新统计,则会进入一次循环统计 
if (mode == COUNT_RECURSIVE) { 
HashPosition pos; 
for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(array), &pos); 
zend_hash_get_current_data_ex(Z_ARRVAL_P(array), (void **) &element, &pos) == SUCCESS; 
zend_hash_move_forward_ex(Z_ARRVAL_P(array), &pos) 
) { 
Z_ARRVAL_P(array)->nApplyCount++; 
cnt += php_count_recursive(*element, COUNT_RECURSIVE TSRMLS_CC); 
Z_ARRVAL_P(array)->nApplyCount--; 
} 
} 
} 
return cnt; 
} 
//文件5:zend/zend_hash.c 
//zend_hash_num_elements的实现 
ZEND_API int zend_hash_num_elements(const HashTable *ht) 
{ 
IS_CONSISTENT(ht); 
return ht->nNumOfElements; 
}
PHP 相关文章推荐
Discuz 模板引擎的封装类代码
Jul 18 PHP
PHP 变量类型的强制转换
Oct 23 PHP
PHP Session_Regenerate_ID函数双释放内存破坏漏洞
Jan 27 PHP
php环境配置之CGI、FastCGI、PHP-CGI、PHP-FPM、Spawn-FCGI比较?
Oct 17 PHP
PHP获取当前url的具体方法全面解析
Nov 26 PHP
PHP中使用Memache作为进程锁的操作类分享
Mar 30 PHP
PHP实现通过URL提取根域名
Mar 31 PHP
php可变长参数处理函数详解
Feb 22 PHP
php使用ftp实现文件上传与下载功能
Jul 21 PHP
总结PHP代码规范、流程规范、git规范
Jun 18 PHP
PHP XML Expat解析器知识点总结
Feb 15 PHP
解决Laravel 使用insert插入数据,字段created_at为0000的问题
Oct 11 PHP
linux下为php添加curl扩展的方法
Jul 29 #PHP
php中修改浏览器的User-Agent来伪装你的浏览器和操作系统
Jul 29 #PHP
php 判断访客是否为搜索引擎蜘蛛的函数代码
Jul 29 #PHP
php.ini中date.timezone设置分析
Jul 29 #PHP
PHP调用Webservice实例代码
Jul 29 #PHP
php和数据库结合的一个简单的web实例 代码分析 (php初学者)
Jul 28 #PHP
一个典型的PHP分页实例代码分享
Jul 28 #PHP
You might like
PHP自定义函数收代码
2010/08/01 PHP
PHP网页游戏学习之Xnova(ogame)源码解读(十六)
2014/06/30 PHP
用nodejs访问ActiveX对象,以操作Access数据库为例。
2011/12/15 NodeJs
js判断IE浏览器版本过低示例代码
2013/11/22 Javascript
Jquery中国地图热点效果-鼠标经过弹出提示层信息的简单实例
2014/02/12 Javascript
浅谈Javascript中匀速运动的停止条件
2014/12/19 Javascript
JavaScript的事件代理和委托实例分析
2015/03/25 Javascript
jQuery实现图片走马灯效果的原理分析
2016/01/16 Javascript
requireJS使用指南
2016/04/27 Javascript
jQuery添加options点击事件并传值实例代码
2016/05/18 Javascript
JS按条件 serialize() 对应标签的使用方法
2017/07/24 Javascript
View.post() 不靠谱的地方你知道多少
2017/08/29 Javascript
jQuery实现的鼠标滚轮控制图片缩放功能实例
2017/10/14 jQuery
微信小程序实现图片上传、删除和预览功能的方法
2017/12/18 Javascript
vue以组件或者插件的形式实现throttle或者debounce
2019/05/22 Javascript
微信小程序实现左侧滑栏过程解析
2019/08/26 Javascript
vue-router之实现导航切换过渡动画效果
2019/10/31 Javascript
node静态服务器实现静态读取文件或文件夹
2019/12/03 Javascript
python虚拟环境 virtualenv的简单使用
2020/01/21 Javascript
手把手带你入门微信小程序新框架Kbone的使用
2020/02/25 Javascript
[03:30]DOTA2完美“圣”典精彩集锦
2016/12/27 DOTA
Python3实现发送QQ邮件功能(附件)
2020/12/23 Python
Python中实现变量赋值传递时的引用和拷贝方法
2018/04/29 Python
python3 中文乱码与默认编码格式设定方法
2018/10/31 Python
python的pstuil模块使用方法总结
2019/07/26 Python
Flask教程之重定向与错误处理实例分析
2019/08/01 Python
python和C++共享内存传输图像的示例
2020/10/27 Python
三星印度官网:Samsung印度
2019/08/03 全球购物
西岭雪山导游词
2015/02/06 职场文书
工作自我评价范文
2015/03/05 职场文书
会计主管岗位职责
2015/04/02 职场文书
2015新员工工作总结范文
2015/10/15 职场文书
python3实现常见的排序算法(示例代码)
2021/07/04 Python
能用CSS实现的就不要麻烦JavaScript了
2021/10/05 HTML / CSS
Java练习之潜艇小游戏的实现
2022/03/16 Java/Android
python 学习GCN图卷积神经网络
2022/05/11 Python