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 相关文章推荐
php基础知识:类与对象(1)
Dec 13 PHP
phpfans留言版用到的数据操作类和分页类
Jan 04 PHP
apache2.2.4+mysql5.0.77+php5.2.8安装精简
Apr 29 PHP
php图片缩放实现方法
Feb 20 PHP
windwos下使用php连接oracle数据库的过程分享
May 26 PHP
PHP彩蛋信息介绍和阻止泄漏的方法(隐藏功能)
Aug 06 PHP
php统计数组元素个数的方法
Jul 02 PHP
PHP入门教程之数学运算技巧总结
Sep 11 PHP
PHP安装BCMath扩展的方法
Feb 13 PHP
关于php开启错误提示的总结
Sep 24 PHP
基于laravel where的高级使用方法
Oct 10 PHP
php面向对象基础详解【星际争霸游戏案例】
Jan 23 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伪造referer突破网盘禁止外连的代码
2008/06/15 PHP
分享下PHP register_globals 值为on与off的理解
2013/09/26 PHP
PHP使用ob_start生成html页面的方法
2014/11/07 PHP
再谈IE中Flash控件的自动激活 ObjectWrap
2007/03/09 Javascript
JavaScript 事件参考手册
2008/12/24 Javascript
Extjs学习过程中新手容易碰到的低级错误积累
2010/02/11 Javascript
JavaScript DOM元素尺寸和位置
2015/04/13 Javascript
详解Matlab中 sort 函数用法
2016/03/20 Javascript
VUEJS实战之修复错误并且美化时间(2)
2016/06/13 Javascript
JS中input表单隐藏域及其使用方法
2017/02/13 Javascript
ES6学习笔记之Set和Map数据结构详解
2017/04/07 Javascript
详解Vue中一种简易路由传参办法
2017/09/15 Javascript
利用js给datalist或select动态添加option选项的方法
2018/01/25 Javascript
详解Vue Elememt-UI构建管理后台
2018/02/27 Javascript
使用淘宝镜像cnpm安装Vue.js的图文教程
2018/05/17 Javascript
vue-cli整合vuex的时候,修改actions和mutations,实现热部署的方法
2018/09/19 Javascript
jQuery.parseJSON()函数详解
2019/02/28 jQuery
layer更改皮肤的实现方法
2019/09/11 Javascript
原生JS实现记忆翻牌游戏
2020/07/31 Javascript
[35:34]Liquid vs Winstrike 2018国际邀请赛小组赛BO2 第一场 8.18
2018/08/19 DOTA
实例讲解Python中的私有属性
2014/08/21 Python
python函数装饰器用法实例详解
2015/06/04 Python
Python中整数的缓存机制讲解
2019/02/16 Python
使用Django开发简单接口实现文章增删改查
2019/05/09 Python
利用 Flask 动态展示 Pyecharts 图表数据方法小结
2019/09/04 Python
python标准库OS模块详解
2020/03/10 Python
Python函数递归调用实现原理实例解析
2020/08/11 Python
波兰珠宝品牌:YES
2019/08/09 全球购物
汉语言文学毕业求职信
2014/07/17 职场文书
个人遵守党的政治纪律情况对照检查材料
2014/09/26 职场文书
2014年企业员工工作总结
2014/12/09 职场文书
基层党建工作简报
2015/07/21 职场文书
学子宴致辞大全
2015/07/27 职场文书
2016庆祝国庆67周年宣传语
2015/11/25 职场文书
Python爬虫基础初探selenium
2021/05/31 Python
使用kubeadm命令行工具创建kubernetes集群
2022/03/31 Servers