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 相关文章推荐
一个程序下载的管理程序(四)
Oct 09 PHP
PHP执行zip与rar解压缩方法实现代码
Dec 05 PHP
php中随机显示图片的函数代码
Jun 23 PHP
修改php.ini以达到屏蔽错误信息并记录日志
Jun 16 PHP
使用php统计字符串中中英文字符的个数
Jun 23 PHP
PHP写的资源下载防盗链类分享
May 12 PHP
php类中的各种拦截器用法分析
Nov 03 PHP
php实现的一个简单json rpc框架实例
Mar 30 PHP
CentOS系统中PHP安装扩展的方式汇总
Apr 09 PHP
PHP使用文件锁解决高并发问题示例
Mar 29 PHP
PHP给前端返回一个JSON对象的实例讲解
May 31 PHP
Laravel解决nesting level错误和隐藏index.php的问题
Oct 12 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 explode()函数用法、切分字符串
2012/10/03 PHP
PHP开发中常见的安全问题详解和解决方法(如Sql注入、CSRF、Xss、CC等)
2014/04/21 PHP
调试PHP程序的多种方法介绍
2014/11/06 PHP
php自动给网址加上链接的方法
2015/06/02 PHP
PHP中的use关键字及文件的加载详解
2016/11/28 PHP
微信开发之获取JSAPI TICKET
2017/07/07 PHP
PHP7 标准库修改
2021/03/09 PHP
javascript firefox兼容ie的dom方法脚本
2008/05/18 Javascript
JavaScript Event学习第三章 早期的事件处理程序
2010/02/07 Javascript
eval与window.eval的差别分析
2011/03/17 Javascript
jquery使用slideDown实现模块缓慢拉出效果的方法
2015/03/27 Javascript
JavaScript数组方法总结分析
2016/05/06 Javascript
超全面的JavaScript开发规范(推荐)
2017/01/21 Javascript
JavaScript输入分钟、秒倒计时技巧总结(附代码)
2017/08/17 Javascript
提升页面加载速度的插件InstantClick
2017/09/12 Javascript
JavaScript面向对象精要(上部)
2017/09/12 Javascript
简单实现jQuery弹窗效果
2017/10/30 jQuery
9种改善AngularJS性能的方法
2017/11/28 Javascript
vue服务端渲染缓存应用详解
2018/09/12 Javascript
基于elementUI实现图片预览组件的示例代码
2019/03/31 Javascript
vue配置文件实现代理v2版本的方法
2019/06/21 Javascript
node.js中process进程的概念和child_process子进程模块的使用方法示例
2020/02/11 Javascript
urllib2自定义opener详解
2014/02/07 Python
Python中对列表排序实例
2015/01/04 Python
研究Python的ORM框架中的SQLAlchemy库的映射关系
2015/04/25 Python
基于python实现名片管理系统
2018/11/30 Python
解决Django删除migrations文件夹中的文件后出现的异常问题
2019/08/31 Python
Django模板获取field的verbose_name实例
2020/05/19 Python
乡镇网格化管理实施方案
2014/03/23 职场文书
出生公证委托书
2014/04/03 职场文书
中国在我心中演讲稿
2014/09/13 职场文书
自我工作评价范文
2015/03/06 职场文书
超市食品安全承诺书
2015/04/29 职场文书
中学生国庆节演讲稿2015
2015/07/30 职场文书
JS继承最简单的理解方式
2021/03/31 Javascript
vue router 动态路由清除方式
2022/05/25 Vue.js