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 相关文章推荐
解析VS2010利用VS.PHP插件调试PHP的方法
Jul 19 PHP
PHP判断表单复选框选中状态完整例子
Jun 24 PHP
Laravel框架学习笔记(一)环境搭建
Oct 15 PHP
PHP连接SQLServer2005的方法
Jan 27 PHP
Yii学习总结之安装配置
Feb 22 PHP
php定义参数数量可变的函数用法实例
Mar 16 PHP
Zend Framework教程之Zend_Layout布局助手详解
Mar 04 PHP
PHP常用的三种设计模式汇总
Aug 28 PHP
php5.3后静态绑定用法详解
Nov 11 PHP
php使用PDO下exec()函数查询执行后受影响行数的方法
Mar 28 PHP
php常用经典函数集锦【数组、字符串、栈、队列、排序等】
Aug 23 PHP
php7 list()、session及其他模块的修改实例分析
May 25 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程序实现支持页面后退的两种方法
2008/06/30 PHP
PHP 批量更新网页内容实现代码
2010/01/05 PHP
php基于单例模式封装mysql类完整实例
2016/10/18 PHP
PHP错误处理函数register_shutdown_function使用示例
2017/07/03 PHP
thinkPHP5框架实现多数据库连接,跨数据连接查询操作示例
2019/05/29 PHP
tp5框架使用cookie加密算法实现登录功能示例
2020/02/10 PHP
新手入门常用代码集锦
2007/01/11 Javascript
js tab 选项卡
2009/04/26 Javascript
jQuery 判断页面元素是否存在的代码
2009/08/14 Javascript
Javascript的&&和||的另类用法
2014/07/23 Javascript
jQuery浏览器CSS3特写兼容实例
2015/01/19 Javascript
javascript验证手机号和实现星号(*)代替实例
2016/08/16 Javascript
js转html实体的方法
2016/09/27 Javascript
js实现的简练高效拖拽功能示例
2016/12/21 Javascript
详解项目升级到vue-cli3的正确姿势
2019/01/28 Javascript
详解如何给React-Router添加路由页面切换时的过渡动画
2019/04/25 Javascript
原生js实现随机点餐效果
2019/12/10 Javascript
python各种语言间时间的转化实现代码
2016/03/23 Python
python将每个单词按空格分开并保存到文件中
2018/03/19 Python
在Windows中设置Python环境变量的实例讲解
2018/04/28 Python
Python3中的列表生成式、生成器与迭代器实例详解
2018/06/11 Python
对Python 窗体(tkinter)树状数据(Treeview)详解
2018/10/11 Python
python 使用递归回溯完美解决八皇后的问题
2020/02/26 Python
使用tensorflow根据输入更改tensor shape
2020/06/23 Python
CSS3中颜色线性渐变实战
2015/07/18 HTML / CSS
HTML5 canvas标签实现刮刮卡效果
2015/04/24 HTML / CSS
html5写一个BUI折叠菜单插件的实现方法
2019/09/11 HTML / CSS
SQL Server笔试题
2012/01/10 面试题
面试后感谢信
2014/02/01 职场文书
模具毕业生推荐信
2014/02/15 职场文书
售后客服个人自我评价
2014/09/14 职场文书
2014四风问题对照检查材料范文
2014/09/15 职场文书
小学教学工作总结2015
2015/05/13 职场文书
公司车队管理制度
2015/08/04 职场文书
十大最强奥特曼武器:怪兽战斗仪在榜,第五奥特之父只使用过一次
2022/03/18 日漫
简单聊聊TypeScript只读修饰符
2022/04/06 Javascript