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 随机排序广告的实现代码
May 09 PHP
php setcookie函数的参数说明及其用法
Apr 20 PHP
php使用递归计算文件夹大小
Dec 24 PHP
[原创]php获取数组中键值最大数组项的索引值
Mar 17 PHP
codeigniter发送邮件并打印调试信息的方法
Mar 21 PHP
PHP中explode函数和split函数的区别小结
Aug 24 PHP
PHP自定义函数实现格式化秒的方法
Sep 14 PHP
php unicode编码和字符串互转的方法
Aug 12 PHP
PHP观察者模式实例分析【对比JS观察者模式】
May 22 PHP
Yii框架中使用PHPExcel的方法分析
Jul 25 PHP
PHP PDO和消息队列的个人理解与应用实例分析
Nov 25 PHP
PHP7修改的函数
Mar 09 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 模拟 asp.net webFrom 按钮提交事件的思路及代码
2013/12/02 PHP
PHP实现链式操作的核心思想
2015/06/23 PHP
Laravel核心解读之异常处理的实践过程
2019/02/24 PHP
PHP如何获取Cookie并实现模拟登录
2020/07/16 PHP
让您的菜单不离网站
2006/10/03 Javascript
用js实现随机返回数组的一个元素
2007/08/13 Javascript
jQuery ajax cache缓存问题
2010/07/01 Javascript
JS获取select的value和text值的简单实例
2014/02/26 Javascript
表单提交前触发函数返回true表单才会提交
2014/03/11 Javascript
innerHTML中标签可以换行的方法汇总
2015/08/14 Javascript
以Python代码实例展示kNN算法的实际运用
2015/10/26 Javascript
JS上传组件FileUpload自定义模板的使用方法
2016/05/10 Javascript
Js获取图片原始宽高的实现代码
2016/05/17 Javascript
Vue关于数据绑定出错解决办法
2017/05/15 Javascript
Vue-cli proxyTable 解决开发环境的跨域问题详解
2017/05/18 Javascript
js实现图片懒加载效果
2017/07/17 Javascript
vue mintui-Loadmore结合实现下拉刷新和上拉加载示例
2017/10/12 Javascript
Vue全局分页组件的实现代码
2018/08/10 Javascript
vue自定义指令的创建和使用方法实例分析
2018/12/04 Javascript
如何优雅的在一台vps(云主机)上面部署vue+mongodb+express项目
2019/01/20 Javascript
javascript实现的图片预览和上传功能示例【兼容IE 9】
2020/05/01 Javascript
使用React代码动态生成栅格布局的方法
2020/05/24 Javascript
[01:27]DOTA2电竞之夜 今夜共饮庆功酒
2014/08/02 DOTA
用Python遍历C盘dll文件的方法
2015/05/06 Python
Python 3实战爬虫之爬取京东图书的图片详解
2017/10/09 Python
Python csv模块使用方法代码实例
2019/08/29 Python
使用TensorFlow直接获取处理MNIST数据方式
2020/02/10 Python
python统计文章中单词出现次数实例
2020/02/27 Python
Django限制API访问频率常用方法解析
2020/10/12 Python
马来西亚在线购物:POPLOOK.com
2019/12/09 全球购物
策划主管的工作职责
2013/11/24 职场文书
自荐信的格式
2014/03/10 职场文书
大跃进口号
2014/06/16 职场文书
golang 如何用反射reflect操作结构体
2021/04/28 Golang
Python 数据可视化之Bokeh详解
2021/11/02 Python
《艾尔登法环》1.03.3补丁上线 碎星伤害调整
2022/04/07 其他游戏