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 相关文章推荐
其他功能
Oct 09 PHP
php 操作符与控制结构
Mar 07 PHP
PHP缓存技术的多种方法小结
Aug 14 PHP
php可生成缩略图的文件上传类实例
Dec 17 PHP
在html文件中也可以执行php语句的方法
Apr 09 PHP
php使用CURL不依赖COOKIEJAR获取COOKIE的方法
Jun 17 PHP
详解WordPress中提醒安装插件以及隐藏插件的功能实现
Dec 25 PHP
WordPress中设置Post Type自定义文章类型的实例教程
May 10 PHP
php版微信公众平台回复中文出现乱码问题的解决方法
Sep 22 PHP
PHPExcel实现表格导出功能示例【带有多个工作sheet】
Jun 13 PHP
php array_chunk()函数用法与注意事项
Jul 12 PHP
Yii框架多语言站点配置方法分析【中文/英文切换站点】
Apr 07 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求小于1000的所有水仙花数的代码
2012/01/10 PHP
浅谈PHP中类和对象的相关函数
2017/04/26 PHP
深入理解PHP中mt_rand()随机数的安全
2017/10/12 PHP
php实现生成带二维码图片并强制下载功能
2018/02/24 PHP
HTTP头隐藏PHP版本号实现过程解析
2020/12/09 PHP
Dom在ajax技术中的作用说明
2010/10/25 Javascript
jQuery中调用WebService方法小结
2011/03/28 Javascript
node.js抓取并分析网页内容有无特殊内容的js文件
2015/11/17 Javascript
AngularJS基础 ng-if 指令用法
2016/08/01 Javascript
json定义及jquery操作json的方法
2016/10/03 Javascript
常用Javascript函数与原型功能收藏(必看篇)
2016/10/09 Javascript
详解webpack 多入口配置
2017/06/16 Javascript
详解require.js配置路径的用法和css的引入
2017/09/06 Javascript
element-ui 关于获取select 的label值方法
2018/08/24 Javascript
vue实现搜索功能
2019/05/28 Javascript
matplotlib设置legend图例代码示例
2017/12/19 Python
浅谈pytorch和Numpy的区别以及相互转换方法
2018/07/26 Python
django admin组件使用方法详解
2019/07/19 Python
Python绘制股票移动均线的实例
2019/08/24 Python
python破解bilibili滑动验证码登录功能
2019/09/11 Python
python实现修改固定模式的字符串内容操作示例
2019/12/30 Python
python 日志模块 日志等级设置失效的解决方案
2020/05/26 Python
HTML5标签大全
2016/11/23 HTML / CSS
SmartBuyGlasses中国:唯视良品(销售名牌太阳镜、墨镜和眼镜框)
2017/07/03 全球购物
享誉全球的多元化时尚精品购物平台:Farfetch发发奇(支持中文)
2017/08/08 全球购物
ZWILLING双立人英国网上商店:德国刀具锅具厨具品牌
2018/05/15 全球购物
CSMA/CD介质访问控制协议
2015/11/17 面试题
盛大笔试题
2016/11/05 面试题
监理资料员岗位职责
2014/01/03 职场文书
国旗下讲话演讲稿
2014/05/08 职场文书
单位绩效考核方案
2014/05/11 职场文书
中职毕业生自我鉴定
2014/09/13 职场文书
个人四风对照检查材料
2014/09/26 职场文书
党的群众路线批评与自我批评发言稿
2014/10/16 职场文书
2015年司机工作总结
2015/04/23 职场文书
springboot+rabbitmq实现智能家居实例详解
2022/07/23 Java/Android