设为首页 收藏本站
查看: 1244|回复: 0

[经验分享] PHP源代码数组统计count分析

[复制链接]

尚未签到

发表于 2015-8-23 12:44:28 | 显示全部楼层 |阅读模式
  偶然在百度知道中看到有个同学问起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 }
  
  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-102973-1-1.html 上篇帖子: [share]PHP购物车类的源码 下篇帖子: Ubuntu 安装 PHP cURL
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表