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 preg_match_all结合str_replace替换内容中所有img
Oct 11 PHP
php 模拟POST|GET操作实现代码
Jul 20 PHP
php 注释规范
Mar 29 PHP
PHP验证码函数代码(简单实用)
Sep 29 PHP
smarty模板局部缓存方法使用示例
Jun 17 PHP
ThinkPHP模板自定义标签使用方法
Jun 26 PHP
PHP5.3新特性小结
Feb 14 PHP
PHP程序员的技术成长规划
Mar 25 PHP
PHP+MySql+jQuery实现的"顶"和"踩"投票功能
May 21 PHP
PHP数据库操作二:memcache用法分析
Aug 16 PHP
PHP5.0 TIDY_PARSE_FILE缓冲区溢出漏洞的解决方案
Oct 14 PHP
laravel5.0在linux下解决.htaccess无效和去除index.php的问题
Oct 16 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获取文件名后缀常用方法小结
2015/02/24 PHP
php实现QQ空间获取当前用户的用户名并生成图片
2015/07/25 PHP
PHP生成各种常见验证码和Ajax验证过程
2016/01/10 PHP
PHP Post获取不到非表单数据的问题解决办法
2018/02/27 PHP
javascript获取作用在元素上面的样式属性代码
2012/09/20 Javascript
动态的改变IFrame的高度实现IFrame自动伸展适应高度
2012/12/28 Javascript
兼容IE和FF的图片上传前预览js代码
2013/05/28 Javascript
jQuery选择器全面总结
2014/01/06 Javascript
javascript的BOM
2016/05/03 Javascript
Bootstrap弹出框(modal)垂直居中的问题及解决方案详解
2016/06/12 Javascript
详解PHP中pathinfo()函数导致的安全问题
2017/01/05 Javascript
angularjs实现猜数字大小功能
2020/05/20 Javascript
微信小程序tabBar模板用法实例分析【附demo源码下载】
2017/11/28 Javascript
vue异步加载高德地图的实现
2018/06/19 Javascript
详解几十行代码实现一个vue的状态管理
2019/01/28 Javascript
mpvue实现微信小程序快递单号查询代码
2020/04/03 Javascript
JS求解两数之和算法详解
2020/04/28 Javascript
基于Web Audio API实现音频可视化效果
2020/06/12 Javascript
[01:01:18]VP vs NIP 2019国际邀请赛小组赛 BO2 第二场 8.15
2019/08/17 DOTA
[08:38]DOTA2-DPC中国联赛 正赛 VG vs Elephant 选手采访
2021/03/11 DOTA
将Emacs打造成强大的Python代码编辑工具
2015/11/20 Python
python抓取网页中图片并保存到本地
2015/12/01 Python
详解Python编程中对Monkey Patch猴子补丁开发方式的运用
2016/05/27 Python
答题辅助python代码实现
2018/01/16 Python
Python实现的求解最小公倍数算法示例
2018/05/03 Python
matplotlib 输出保存指定尺寸的图片方法
2018/05/24 Python
Python骚操作之动态定义函数
2019/03/26 Python
Python使用ffmpy将amr格式的音频转化为mp3格式的例子
2019/08/08 Python
pycharm实现在虚拟环境中引入别人的项目
2020/03/09 Python
html5利用canvas绘画二级树形结构图的示例
2017/09/27 HTML / CSS
生物有机护肤品:Aurelia Probiotic Skincare
2018/01/31 全球购物
Vans(范斯)新西兰官方网站:美国原创极限运动品牌
2020/09/19 全球购物
C语言笔试集
2012/07/24 面试题
大学生社会实践自我鉴定
2014/03/24 职场文书
交警个人先进事迹材料
2014/05/11 职场文书
浅谈Web Storage API的使用
2021/06/23 Javascript