PHP函数count、strlen效率分析

一直纠结PHP中统计数组长度函数count(),还有strlen是怎么的,它的效率是O(1)还是O(n)呢?最近看PHP源码,总结了下。分析如下:

zend给php的所有变量都用共用体的方式去保存,而字符串的保存和数组的保存也是不同的,数组采用的是hash表的方式去保存。PHP的变量共用体描述如下

/*
    * 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;
zend_uchar type; /* active type */
zend_uchar is_ref;
};

哈希表的结构是这样的:

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中的宏定义来获取:

#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,这个mode参数指明了,是否需要重新统计,而它的重新统计将会遍历一次数组,效率上是O(N)[N:长度],默认情况下是不重新统计,那这个时候将会直接输出hashtable中的nNumOfElements,此时的效率也是O(1)次:count代码如下:

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;
} 

//zend/zend_hash.c
//zend_hash_num_elements的实现
ZEND_API int zend_hash_num_elements(const HashTable *ht)
{
IS_CONSISTENT(ht); 

return ht->nNumOfElements;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-06 03:53:16

PHP函数count、strlen效率分析的相关文章

x86的ABI(C函数实现原理)分析

This article is aim to explain how to use assemble language realize those common function in C. But I fail to get a simple method to introduce it because of some reasons . I will try to extract some key point at this article. Then analysize a example

LayoutInflater效率分析及源码跟踪

一.效率分析 测试设备 测试设配:魅族MX4 操作系统:Android5.1操作系统 CPU型号:联发科MT6595 内存: 2GB 测试方法 使用LayoutInflater对3组不同复杂度的xml布局进行解析,每次解析100次,测试10次,求其100次的平均运行时间.单位为ms. 测试结果 | | Xml文件 |Time(ms/100)| |---------------|-----------------------|------------| |第一组(简单) |深度2节点4 属性30个

oracle中的聚合函数count、max、min、sum、avg以及NVL函数的用法

oracle中的聚合函数count.max.min.sum.avg以及NVL函数的用法 分组函数聚合函数对一组行中的某个列执行计算执行计算并返回单一的值.聚合函数忽略空值.聚合函数经常与 SELECT 语句的 GROUP BY 子句一同使用,所以有的时候也把其称之为分组函数.这类函数通常应用于报表统计中,以下展示Oracle常用的聚合函数的应用. 分组函数的介绍 作用于一组数据,并对一组数据返回一个值. 常见的分组函数有: Count 用来计算有效数据的数量 Min 返回一个数字列或计算列的最小

mysql source命令导入sql文件效率分析

Query OK, 24918 rows affected (0.90 sec)Records: 24918  Duplicates: 0  Warnings: 0Query OK, 24923 rows affected (2.26 sec)Records: 24923  Duplicates: 0  Warnings: 0Query OK, 24924 rows affected (2.74 sec)Records: 24924  Duplicates: 0  Warnings: 0Quer

Project Euler 第一题效率分析

Project Euler: 欧拉计划是一系列挑战数学或者计算机编程问题,解决这些问题需要的不仅仅是数学功底. 启动这一项目的目的在于,为乐于探索的人提供一个钻研其他领域并且学习新知识的平台,将这一平台打造一个有趣和休闲 的环境. 项目主页:https://projecteuler.net 第一题 Multiples of 3 and 5 If we list all the natural numbers below 10 that are multiples of 3 or 5, we ge

团队工作效率分析工具gitstats

如果你是团队领导,关心团队的开发效率和工作激情:如果你是开源软件开发者,维护者某个repo:又或者,你关心某个开源软件的开发进度,那么你可以试一试gitstats. gitstats 是一个git仓库分析软件,可以帮助你查看git仓库的状态,自动生成数据图表. 安装使用非常简单,如果是ubuntu,直接apt-get 即可.如果是mac,那还得装个gnuPlot. 首先,gitstats提供全局上的统计数据报告,包括: 1. 报告产生时间及产生所花费的时间:仅花了28秒2. 报告所覆盖的时间:2

数据结构-排序算法时间和空间效率分析

排序的效率分析 不稳定:选择排序.快速排序.希尔排序.堆排序 稳定:冒泡排序.插入排序.归并排序.基数排序

声笔自然单字效率分析

-----------------------声笔自然单字效率分析-------------------------- 2   keys: 21        items, 99116052.00     times, covering 17.50 % 2   keys: 21        items, 99116052.00     times, covering 17.50 %  3   keys: 2016      items, 372140662.00    times, cover

计算一段函数的执行效率

int main() { clock_t startTime = 0, endTime = 0;    startTime = clock(); //要执行的函数 endTime = clock();    int lastTime = endTime - startTime; } 计算一段函数的执行效率