zend给php的所有变量都用结构的方式去保存,而字符串的保存和数组的保存也是不同的,数组采用的是hash表的方式去保存(大家知道hash保存的地址有效的减少冲突-hash散列表的概念你懂的),而在php中的结构体上表现如下: <div class="codetitle"><a style="CURSOR: pointer" data="74438" class="copybut" id="copybut74438" onclick="doCopy('code74438')"> 代码如下:<div class="codebody" id="code74438"> //文件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中的宏定义来获取: <div class="codetitle"><a style="CURSOR: pointer" data="66152" class="copybut" id="copybut66152" onclick="doCopy('code66152')"> 代码如下:<div class="codebody" id="code66152"> //文件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代码如下: <div class="codetitle"><a style="CURSOR: pointer" data="44125" class="copybut" id="copybut44125" onclick="doCopy('code44125')"> 代码如下:<div class="codebody" id="code44125"> //文件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; }
(编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|