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
Snoopy类使用小例子
Apr 15 PHP
php网上商城购物车设计代码分享
Feb 15 PHP
关于shopex同步ucenter的redirect问题,导致script不运行
Apr 10 PHP
php使用百度ping服务代码实例
Jun 19 PHP
PHP如何通过传引用的思想实现无限分类(代码简单)
Oct 13 PHP
Smarty日期时间操作方法示例
Nov 15 PHP
PHP实现图的邻接矩阵表示及几种简单遍历算法分析
Nov 24 PHP
php实现socket推送技术的示例
Dec 20 PHP
PHP PDOStatement::setFetchMode讲解
Feb 03 PHP
Thinkphp5框架使用validate实现验证功能的方法
Aug 27 PHP
利用ajax+php实现商品价格计算
Mar 31 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
文件上传程序的全部源码
2006/10/09 PHP
Linux下进行MYSQL编程时插入中文乱码的解决方案
2007/03/15 PHP
php 备份数据库代码(生成word,excel,json,xml,sql)
2013/06/23 PHP
php 如何禁用eval() 函数实例详解
2016/12/01 PHP
基于PHP-FPM进程池探秘
2017/10/17 PHP
jquery简单瀑布流实现原理及ie8下测试代码
2013/01/23 Javascript
node.js中的require使用详解
2014/12/15 Javascript
jquery通过扩展select控件实现支持enter或focus选择的方法
2015/11/19 Javascript
javascript编程异常处理实例小结
2015/11/30 Javascript
原生JavaScript制作微博发布面板效果
2016/03/11 Javascript
jQuery中select与datalist制作下拉菜单时的区别浅析
2016/12/30 Javascript
AngularJS执行流程详解
2017/02/17 Javascript
Angular.js初始化之ng-app的自动绑定与手动绑定详解
2017/07/31 Javascript
jquery.pagination.js分页使用教程
2018/10/23 jQuery
新手快速上手webpack4打包工具的使用详解
2019/01/28 Javascript
Node.js + express实现上传大文件的方法分析【图片、文本文件】
2019/03/14 Javascript
jQuery实现文本显示一段时间后隐藏的方法分析
2019/06/20 jQuery
vue集成chart.js的实现方法
2019/08/20 Javascript
VUE路由动态加载实例代码讲解
2019/08/26 Javascript
微信小程序swiper左右扩展各显示一半代码实例
2019/12/05 Javascript
Sublime Text3 配置 NodeJs 环境的方法
2020/05/20 NodeJs
nuxt 每个页面head标签内容设置方式
2020/11/05 Javascript
Python写的创建文件夹自定义函数mkdir()
2014/08/25 Python
Python中查看文件名和文件路径
2017/03/31 Python
Python 存取npy格式数据实例
2020/07/01 Python
详解WebSocket跨域问题解决
2018/08/06 HTML / CSS
全球工业:Global Industrial
2020/02/01 全球购物
医院护士的求职信
2014/01/03 职场文书
幼儿园中班教师寄语
2014/04/03 职场文书
摄影专业毕业生求职信
2014/08/05 职场文书
暑期学习心得体会
2014/09/02 职场文书
团委工作总结2015
2015/04/02 职场文书
雾霾停课通知
2015/04/24 职场文书
起诉书格式范文
2015/05/20 职场文书
2016年秋季运动会广播稿
2015/12/21 职场文书
吃通javascript正则表达式
2021/04/21 Javascript