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作的文本留言本的例子(一)
Oct 09 PHP
默默小谈PHP&MYSQL分页原理及实现
Jan 02 PHP
php中将时间差转换为字符串提示的实现代码
Aug 08 PHP
探讨:使用XMLSerialize 序列化与反序列化
Jun 08 PHP
php查看网页源代码的方法
Mar 13 PHP
PHP中的流(streams)浅析
Jul 02 PHP
浅谈PHP中foreach/in_array的使用
Nov 02 PHP
yii2实现根据时间搜索的方法
May 25 PHP
php通过文件头判断格式的方法
May 28 PHP
PHP+Redis 消息队列 实现高并发下注册人数统计的实例
Jan 29 PHP
php关联数组与索引数组及其显示方法
Mar 12 PHP
laravel框架模板之公共模板、继承、包含实现方法分析
Aug 30 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
彻底删除thinkphp3.1案例blog标签的方法
2014/12/05 PHP
php获取文件类型和文件信息的方法
2015/07/10 PHP
PHP操作MySQL的mysql_fetch_* 函数的常见用法教程
2015/12/25 PHP
instanceof和typeof运算符的区别详解
2014/01/06 Javascript
js实现省市联动效果的简单实例
2014/02/10 Javascript
如何正确使用Nodejs 的 c++ module 链接到 OpenSSL
2014/08/03 NodeJs
jQuery on方法传递参数示例
2014/12/09 Javascript
jquery插件splitScren实现页面分屏切换模板特效
2015/06/16 Javascript
Bootstrap每天必学之按钮(一)
2015/11/24 Javascript
bootstrap-treeview自定义双击事件实现方法
2016/01/09 Javascript
jquery+css3实现会动的小圆圈效果
2016/01/27 Javascript
基于jQuery实现仿微博发布框字数提示
2016/07/27 Javascript
AngularJS 中的事件详解
2016/07/28 Javascript
微信小程序 列表的上拉加载和下拉刷新的实现
2017/04/01 Javascript
knockoutjs模板实现树形结构列表
2017/07/31 Javascript
Vue.directive 自定义指令的问题小结
2018/03/04 Javascript
vue-router二级导航切换路由及高亮显示的实现方法
2019/07/10 Javascript
vue中组件通信详解(父子组件, 爷孙组件, 兄弟组件)
2020/07/27 Javascript
JavaScript 中的六种循环方法
2021/01/06 Javascript
Python open读写文件实现脚本
2008/09/06 Python
python发送HTTP请求的方法小结
2015/07/08 Python
在Python中定义和使用抽象类的方法
2016/06/30 Python
Python实现选择排序
2017/06/04 Python
python之Character string(实例讲解)
2017/09/25 Python
Python基础练习之用户登录实现代码分享
2017/11/08 Python
Python如何定义接口和抽象类
2020/07/28 Python
python 带时区的日期格式化操作
2020/10/23 Python
详解CSS3阴影 box-shadow的使用和技巧总结
2016/12/03 HTML / CSS
日本索尼音乐商店:Sony Music Shop
2018/07/17 全球购物
个人求职简历的自我评价
2013/10/19 职场文书
我为自己代言广告词
2014/03/18 职场文书
国际会计专业求职信
2014/08/04 职场文书
学生评语集锦
2015/01/04 职场文书
学校办公室主任岗位职责
2015/04/01 职场文书
一封真诚的自荐信帮你赢得机会
2019/05/07 职场文书
导游词之阳朔遇龙河
2019/12/16 职场文书