phpcount数组报错_PHP源代码数组统计count分析

简介:这是PHP源代码数组统计count分析的详细页面,介绍了和php,有关的知识、技巧、经验,和一些php源码等。 class='pingjiaF' frameborder='0' src='http://biancheng.dnbcw.info/pingjia.php?id=342715' scrolling='no'>

偶然在百度知道中看到有个同学问起count及strlen的效率《http://zhidao.baidu.com/question/300773887.html》的问题,好吧这个问题我当初没理解透彻,认为其不属两个不一样的东西不可比较,后来看了楼主的回复才反应过来,所以自己也去找了下源码查看下。现在总结下查看到的结果并记录之。

zend给php的所有变量都用结构的方式去保存,而字符串的保存和数组的保存也是不同的,数组采用的是hash表的方式去保存(大家知道hash保存的地址有效的减少冲突-hash散列表的概念你懂的),而在php中的结构体上表现如下:

1 //文件1:zend/zend.h

2 /*

3 * zval

4 */

5 typedef struct _zval_struct zval;

6 ...

7 typedef union _zvalue_value {

8 long lval; /* long value */

9 double dval; /* double value */

10 struct {

11 char *val;

12 int len;

13 } str;

14 HashTable *ht; /* hash table value */

15 zend_object_value obj;

16 } zvalue_value;

17

18 struct _zval_struct {

19 /* Variable information */

20 zvalue_value value; /* value */

21 zend_uint refcount__gc;

22 zend_uchar type; /* active type */

23 zend_uchar is_ref__gc;

24 };

25 //hash表的结构如下

26 //文件2:zend/zend_hash.h

27 typedef struct _hashtable {

28 uint nTableSize;

29 uint nTableMask;

30 uint nNumOfElements;

31 ulong nNextFreeElement;

32 Bucket *pInternalPointer; /* Used for element traversal */

33 Bucket *pListHead;

34 Bucket *pListTail;

35 Bucket **arBuckets;

36 dtor_func_t pDestructor;

37 zend_bool persistent;

38 unsigned char nApplyCount;

39 zend_bool bApplyProtection;

40 #if ZEND_DEBUG

41 int inconsistent;

42 #endif

43 } HashTable;

一般的变量(字符串)在使用strlen获取长度的时候,其实获取的就是zvalue_value.str这个结构中的len属性,效率上O(1)次,特别说明的一点是:strlen在php中并没有核心的实现,而是在使用了zend中的宏定义来获取:

1 //文件3:zend/zend_operators.php

2 #define Z_STRLEN(zval) (zval).value.str.len

3 ...

4 #define Z_STRLEN_P(zval_p) Z_STRLEN(*zval_p)

5 ...

6 #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代码如下:

1 //文件4:ext/standard/array.c

2 PHP_FUNCTION(count)

3 {

4 zval *array;

5 long mode = COUNT_NORMAL;

6

7 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &array, &mode) == FAILURE) {

8 return;

9 }

10

11 switch (Z_TYPE_P(array)) {

12 case IS_NULL:

13 RETURN_LONG(0);

14 break;

15 case IS_ARRAY:

16 RETURN_LONG (php_count_recursive (array, mode TSRMLS_CC));

17 break;

18 .....

19

20 //php_count_recursive的实现

21 static int php_count_recursive(zval *array, long mode TSRMLS_DC) /* {{{ */

22 {

23 long cnt = 0;

24 zval **element;

25

26 if (Z_TYPE_P(array) == IS_ARRAY) {

27 //错误处理

28 if (Z_ARRVAL_P(array)->nApplyCount > 1) {

29 php_error_docref(NULL TSRMLS_CC, E_WARNING, "recursion detected");

30 return 0;

31 }

32 //通过zend_hash_num_elements直接获得长度

33 cnt = zend_hash_num_elements(Z_ARRVAL_P(array));

34

35 //如果指定了需要重新统计,则会进入一次循环统计

36 if (mode == COUNT_RECURSIVE) {

37 HashPosition pos;

38

39 for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(array), &pos);

40 zend_hash_get_current_data_ex(Z_ARRVAL_P(array), (void **) &element, &pos) == SUCCESS;

41 zend_hash_move_forward_ex(Z_ARRVAL_P(array), &pos)

42 ) {

43 Z_ARRVAL_P(array)->nApplyCount++;

44 cnt += php_count_recursive(*element, COUNT_RECURSIVE TSRMLS_CC);

45 Z_ARRVAL_P(array)->nApplyCount--;

46 }

47 }

48 }

49

50 return cnt;

51 }

52

53 //文件5:zend/zend_hash.c

54 //zend_hash_num_elements的实现

55 ZEND_API int zend_hash_num_elements(const HashTable *ht)

56 {

57 IS_CONSISTENT(ht);

58

59 return ht->nNumOfElements;

60 }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值