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 02 PHP
浅谈web上存漏洞及原理分析、防范方法(文件名检测漏洞)
Jun 29 PHP
php导出word文档与excel电子表格的简单示例代码
Mar 08 PHP
PHPAnalysis中文分词类详解
Jun 13 PHP
php数组分页实现方法
Apr 30 PHP
thinkphp表单上传文件并将文件路径保存到数据库中
Jul 28 PHP
PHP Header用于页面跳转时的几个注意事项
Oct 21 PHP
php实现文件预览功能
May 23 PHP
PHP根据树的前序遍历和中序遍历构造树并输出后序遍历的方法
Nov 10 PHP
PHP封装XML和JSON格式数据接口操作示例
Mar 06 PHP
laravel-admin 实现给grid的列添加行数序号的方法
Oct 08 PHP
PHP扩展类型及安装方式解析
Apr 27 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
2019年漫画销量排行榜:鬼灭登顶 海贼单卷制霸 尾田盛赞鬼灭
2020/03/08 日漫
PHP单态模式简单用法示例
2016/11/16 PHP
php使用ftp实现文件上传与下载功能
2017/07/21 PHP
php数据库的增删改查 php与javascript之间的交互
2017/08/31 PHP
php 多个变量指向同一个引用($b = &$a)用法分析
2019/11/13 PHP
PHP的new static和new self的区别与使用
2019/11/27 PHP
网页图片延时加载的js代码
2010/04/22 Javascript
jQuery validate 中文API 附validate.js中文api手册
2010/07/31 Javascript
15款优秀的jQuery导航菜单插件分享
2011/07/19 Javascript
jQuery $.get 的妙用 访问本地文本文件
2012/07/12 Javascript
js使浏览器窗口最大化实现代码(适用于IE)
2013/08/07 Javascript
jquery实现带渐变淡入淡出并向右依次展开的多级菜单效果实例
2015/08/22 Javascript
大型JavaScript应用程序架构设计模式
2016/06/29 Javascript
KnockoutJS 3.X API 第四章之数据控制流with绑定
2016/10/10 Javascript
在vue-cli项目中使用bootstrap的方法示例
2018/04/21 Javascript
Webpack的dll功能使用
2018/06/28 Javascript
d3绘制基本的柱形图的实现代码
2018/12/12 Javascript
JS面向对象之单选框实现
2020/01/17 Javascript
[03:14]辉夜杯主赛事 12月25日每日之星
2015/12/26 DOTA
Python urllib、urllib2、httplib抓取网页代码实例
2015/05/09 Python
Python MySQL数据库连接池组件pymysqlpool详解
2017/07/07 Python
Python实现接受任意个数参数的函数方法
2018/04/21 Python
Python利用ORM控制MongoDB(MongoEngine)的步骤全纪录
2018/09/13 Python
Linux下安装python3.6和第三方库的教程详解
2018/11/09 Python
Python Opencv任意形状目标检测并绘制框图
2019/07/23 Python
Python Django中间件,中间件函数,全局异常处理操作示例
2019/11/08 Python
python数据预处理 :数据抽样解析
2020/02/24 Python
jupyter notebook的安装与使用详解
2020/05/18 Python
html5-Canvas可以在web中绘制各种图形
2012/12/26 HTML / CSS
怀旧收藏品和经典纪念品:Betty’s Attic
2018/08/29 全球购物
Under Armour安德玛英国官网:美国高端运动科技品牌
2018/09/17 全球购物
民主评议党员自我鉴定
2014/10/21 职场文书
2015会计试用期工作总结
2014/12/12 职场文书
餐饮服务员岗位职责
2015/02/09 职场文书
Mysql案例刨析事务隔离级别
2021/09/25 MySQL
Java由浅入深通关抽象类与接口(下篇)
2022/04/26 Java/Android