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 相关文章推荐
PHP4在WinXP下IIS和Apache2服务器上的安装实例
Oct 09 PHP
用缓存实现静态页面的测试
Dec 06 PHP
PHP+Mysql+jQuery实现动态展示信息
Oct 08 PHP
php表单请求获得数据求和示例
May 15 PHP
PHP递归遍历指定目录的文件并统计文件数量的方法
Mar 24 PHP
Symfony2使用第三方库Upload制作图片上传实例详解
Feb 04 PHP
Yii2如何批量添加数据
May 17 PHP
基于Codeigniter框架实现的student信息系统站点动态发布功能详解
Mar 23 PHP
Yii框架批量插入数据扩展类的简单实现方法
May 23 PHP
PHP大文件切割上传功能实例分析
Jul 01 PHP
laravel 实现关闭CSRF(全部关闭、部分关闭)
Oct 21 PHP
PHP实现长轮询消息实时推送功能代码实例讲解
Feb 26 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 ADODB使用方法集锦
2008/03/25 PHP
MySQL的FIND_IN_SET函数使用方法分享
2012/03/27 PHP
Destoon实现多表查询示例
2014/08/21 PHP
PHP动态生成指定大小随机图片的方法
2016/03/25 PHP
JQuery for与each性能比较分析
2013/05/14 Javascript
jquery隐藏标签和显示标签的实例
2013/11/11 Javascript
自定义的一个简单时尚js下拉选择框
2013/11/20 Javascript
基于BootStrap Metronic开发框架经验小结【一】框架总览及菜单模块的处理
2016/05/12 Javascript
基于Bootstrap实现的下拉菜单手机端不能选择菜单项的原因附解决办法
2016/07/22 Javascript
jquery删除table当前行的实例代码
2016/10/07 Javascript
原生JS+HTML5实现跟随鼠标一起流动的粒子动画效果
2018/05/03 Javascript
Element的el-tree控件后台数据结构的生成以及方法的抽取
2020/03/05 Javascript
keep-alive不能缓存多层级路由菜单问题解决
2020/03/10 Javascript
layui使用及简单的三级联动实现教程
2020/12/01 Javascript
[05:01]3.19DOTA2发布会 我们都是刀塔人
2014/03/25 DOTA
Python中有趣在__call__函数
2015/06/21 Python
python xml解析实例详解
2016/11/14 Python
Python探索之静态方法和类方法的区别详解
2017/10/27 Python
Python编程之黑板上排列组合,你舍得解开吗
2017/10/30 Python
Python数据类型中的“冒号“[::]——分片与步长操作示例
2018/01/24 Python
numpy linalg模块的具体使用方法
2019/05/26 Python
matplotlib部件之矩形选区(RectangleSelector)的实现
2021/02/01 Python
突袭HTML5之Javascript API扩展3—本地存储全新体验
2013/01/31 HTML / CSS
html5贪吃蛇游戏使用63行代码完美实现
2013/06/25 HTML / CSS
伦敦著名的运动鞋综合商店:Footpatrol
2019/03/25 全球购物
CAT鞋加拿大官网:CAT Footwear加拿大
2020/08/05 全球购物
C#怎么让一个窗口居中显示?
2015/10/20 面试题
Python面试题:如何用Python来发送邮件
2016/03/15 面试题
先进班级集体事迹材料
2014/01/30 职场文书
优秀公益广告词大全
2014/03/19 职场文书
青奥会口号
2014/06/12 职场文书
党员个人剖析材料
2014/09/30 职场文书
2014年宣传工作总结
2014/11/18 职场文书
2014年实习生工作总结
2014/11/27 职场文书
Nginx服务器添加Systemd自定义服务过程解析
2021/03/31 Servers
MYSQL(电话号码,身份证)数据脱敏的实现
2021/05/28 MySQL