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 相关文章推荐
Zend公司全球首推PHP认证
Oct 09 PHP
用windows下编译过的eAccelerator for PHP 5.1.6实现php加速的使用方法
Sep 30 PHP
php 8小时时间差的解决方法小结
Dec 22 PHP
is_uploaded_file函数引发的不能上传文件问题
Oct 29 PHP
设置php页面编码的两种方法示例介绍
Mar 03 PHP
php中get_meta_tags()、CURL与user-agent用法分析
Dec 16 PHP
php 类自动载入的方法
Jun 03 PHP
PHP利用imagick生成组合缩略图
Feb 19 PHP
PHP从二维数组得到N层分类树的实现代码
Oct 11 PHP
PHP实现登陆表单提交CSRF及验证码
Jan 24 PHP
ThinkPHP Where 条件中常用表达式示例(详解)
Mar 31 PHP
Yii2.0使用阿里云OSS的SDK上传图片、下载、删除图片示例
Sep 20 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
PHP5.0正式发布 不完全兼容PHP4 新增多项功能
2006/10/09 PHP
一个php导出oracle库的php代码
2009/04/20 PHP
五款PHP代码重构工具推荐
2014/10/14 PHP
js读取本地excel文档数据的代码
2010/11/11 Javascript
js判断IE6/IE7/FF的代码[XMLHttpRequest]
2011/02/16 Javascript
Ext JS 4实现带week(星期)的日期选择控件(实战一)
2013/08/21 Javascript
使用jQuery仿苹果官网焦点图特效
2014/12/23 Javascript
详解Jquery的事件操作和文档操作
2016/12/19 Javascript
JS实现的模仿QQ头像资料卡显示与隐藏效果
2017/04/07 Javascript
jQuery实现滚动到底部时自动加载更多的方法示例
2018/02/18 jQuery
layui实现图片虚拟路径上传,预览和删除的例子
2019/09/25 Javascript
微信小程序监听用户登录事件的实现方法
2019/11/11 Javascript
javascript实现智能手环时间显示
2020/09/18 Javascript
[02:18]DOTA2英雄基础教程 育母蜘蛛
2014/01/20 DOTA
[01:44]Ti10举办地公布
2019/08/25 DOTA
[45:59]完美世界DOTA2联赛PWL S2 FTD vs GXR 第二场 11.22
2020/11/24 DOTA
python批量复制图片到另一个文件夹
2018/09/17 Python
pytorch permute维度转换方法
2018/12/14 Python
Python 正则表达式匹配字符串中的http链接方法
2018/12/25 Python
python 图像平移和旋转的实例
2019/01/10 Python
解决webdriver.Chrome()报错:Message:'chromedriver' executable needs to be in Path
2019/06/12 Python
Python 用matplotlib画以时间日期为x轴的图像
2019/08/06 Python
贝玲妃美国官方网站:Benefit美国
2016/08/28 全球购物
Java软件工程师综合面试题笔试题
2013/09/08 面试题
机械设计职业生涯规划书
2013/12/27 职场文书
函授教育个人学习的自我评价
2013/12/31 职场文书
2014年教师节寄语
2014/04/03 职场文书
初中班主任评语大全
2014/04/24 职场文书
多媒体编辑专业毕业生求职信
2014/06/13 职场文书
银行贷款收入证明
2014/10/17 职场文书
2014年扶贫工作总结
2014/11/18 职场文书
关于军训的感想
2015/08/07 职场文书
怎样写好工作计划
2019/04/10 职场文书
使用vue-element-admin框架从后端动态获取菜单功能的实现
2021/04/29 Vue.js
Golang实现AES对称加密的过程详解
2021/05/20 Golang
JavaScript parseInt0.0000005打印5原理解析
2022/07/23 Javascript