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模板之Phpbean的目录结构
Jan 10 PHP
elgg 获取文件图标地址的方法
Mar 20 PHP
PHP 删除一个目录及目录下的所有文件的函数代码
May 26 PHP
php设计模式之命令模式使用示例
Mar 02 PHP
php二维码生成
Oct 19 PHP
php构造方法中析构方法在继承中的表现
Apr 12 PHP
PHP加密解密类实例代码
Jul 20 PHP
PHP中的正则表达式实例详解
Apr 25 PHP
深入解析Laravel5.5中的包自动发现Package Auto Discovery
Sep 13 PHP
PHP实现在对象之外访问其私有属性private及保护属性protected的方法
Nov 20 PHP
Docker搭建自己的PHP开发环境
Feb 24 PHP
PHP filesize函数用法浅析
Feb 15 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动态生成VRML网页
2006/10/09 PHP
php数组总结篇(一)
2008/09/30 PHP
用PHP即时捕捉PHP中的错误并发送email通知的实现代码
2013/01/19 PHP
PHP实现根据设备类型自动跳转相应页面的方法
2014/07/24 PHP
javascript arguments 传递给函数的隐含参数
2009/08/21 Javascript
12款经典的白富美型—jquery图片轮播插件—前端开发必备
2013/01/08 Javascript
全面理解面向对象的 JavaScript(来自ibm)
2013/11/10 Javascript
JS处理json日期格式化问题
2015/10/01 Javascript
基于jQuery实现Tabs选项卡自定义插件
2016/11/21 Javascript
jQuery实现二维码扫描功能
2017/01/09 Javascript
JavaScript实现父子dom同时绑定两个点击事件,一个用捕获,一个用冒泡时执行顺序的方法
2017/03/30 Javascript
Angular.js中下拉框实现渲染html的方法
2017/06/18 Javascript
详解如何在vue中使用sass
2017/06/21 Javascript
微信小程序使用modal组件弹出对话框功能示例
2017/11/29 Javascript
VUE中使用MUI方法
2019/02/12 Javascript
基于JavaScript实现表格隔行换色
2020/05/08 Javascript
微信小程序语音同步智能识别的实现案例代码解析
2020/05/29 Javascript
vue中是怎样监听数组变化的
2020/10/24 Javascript
Win7下搭建python开发环境图文教程(安装Python、pip、解释器)
2016/05/17 Python
Python实现的爬取小说爬虫功能示例
2019/03/30 Python
详解python opencv、scikit-image和PIL图像处理库比较
2019/12/26 Python
Python3 Tensorlfow:增加或者减小矩阵维度的实现
2020/05/22 Python
keras-siamese用自己的数据集实现详解
2020/06/10 Python
python接口自动化框架实战
2020/12/23 Python
css3实现信纸/同学录效果的示例代码
2018/12/11 HTML / CSS
HTML5拖放功能_动力节点Java学院整理
2017/07/13 HTML / CSS
会计专业毕业生自我评价
2013/09/25 职场文书
学校联谊协议书
2014/09/16 职场文书
幼师个人总结范文
2015/02/28 职场文书
新闻稿标题
2015/07/18 职场文书
2016年“我们的节日·重阳节”主题活动总结
2016/04/01 职场文书
2019幼儿教师求职信(3篇)
2019/09/20 职场文书
如何正确理解python装饰器
2021/06/15 Python
CSS中Single Div 绘图技巧的实现
2021/06/18 HTML / CSS
Java SSM配置文件案例详解
2021/08/30 Java/Android
如何使用SQL Server语句创建表
2022/04/12 SQL Server