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和ACCESS写聊天室(十)
Oct 09 PHP
推荐个功能齐全的发送PHP邮件类
Jan 03 PHP
获取远程文件大小的php函数
Jan 11 PHP
ecshop 订单确认中显示省市地址信息的方法
Mar 15 PHP
php 常用算法和时间复杂度
Jul 01 PHP
WordPress中转义HTML与过滤链接的相关PHP函数使用解析
Dec 22 PHP
thinkphp3.x中变量的获取和过滤方法详解
May 20 PHP
PHP排序算法之直接插入排序(Straight Insertion Sort)实例分析
Apr 20 PHP
PHP的JSON封装、转变及输出操作示例
Sep 27 PHP
laravel 关联关系遍历数组的例子
Oct 10 PHP
Laravel框架Eloquent ORM简介、模型建立及查询数据操作详解
Dec 04 PHP
MacOS下PHP7.1升级到PHP7.4.15的方法
Feb 22 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
索尼SONY ICF-7600A(W)电路分析
2021/03/01 无线电
解决PHP在DOS命令行下却无法链接MySQL的技术笔记
2010/12/29 PHP
给初学者的30条PHP最佳实践(荒野无灯)
2011/08/02 PHP
php addslashes及其他清除空格的方法是不安全的
2012/01/25 PHP
php smarty truncate UTF8乱码问题解决办法
2014/06/13 PHP
php实现的常见排序算法汇总
2014/09/08 PHP
PHP return语句另类用法不止是在函数中
2014/09/17 PHP
php使用fopen创建utf8编码文件的方法
2014/10/31 PHP
PHP的Trait机制原理与用法分析
2019/10/18 PHP
javascript 放大镜 v1.0 基于Yui2 实现的放大镜效果
2010/03/08 Javascript
js获取或设置当前窗口url参数的小例子
2013/10/14 Javascript
js Date概念详细介绍
2013/11/22 Javascript
Javascript学习指南
2014/12/01 Javascript
AngularJS学习笔记之ng-options指令
2015/06/16 Javascript
Select下拉框模糊查询功能实现代码
2016/07/22 Javascript
NodeJS远程代码执行
2016/08/28 NodeJs
详解vue嵌套路由-params传递参数
2017/05/23 Javascript
详解Vue.js中.native修饰符
2018/04/24 Javascript
vue项目动态设置页面title及是否缓存页面的问题
2018/11/08 Javascript
Moment.js实现多个同时倒计时
2019/08/26 Javascript
JavaScript Canvas编写炫彩的网页时钟
2019/10/16 Javascript
vue和小程序项目中使用iconfont的方法
2020/05/19 Javascript
Python使用代理抓取网站图片(多线程)
2014/03/14 Python
Python中正则表达式的用法实例汇总
2014/08/18 Python
Windows和Linux下Python输出彩色文字的方法教程
2017/05/02 Python
使用pandas读取文件的实现
2019/07/31 Python
Python xlwings插入Excel图片的实现方法
2021/02/26 Python
荷兰男士时尚网上商店:Suitable
2017/12/25 全球购物
医院护士求职自荐信格式
2013/09/21 职场文书
2014新年元旦活动策划方案
2014/02/18 职场文书
派出所所长先进事迹
2014/05/19 职场文书
五四青年节演讲稿
2014/05/26 职场文书
2014年乡镇工会工作总结
2014/12/02 职场文书
驳回起诉裁定书
2015/05/19 职场文书
MySql学习笔记之事务隔离级别详解
2021/05/12 MySQL
详解Nginx的超时keeplive_timeout配置步骤
2022/05/25 Servers