微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

PHP源代码数组统计count分析

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

原文地址:https://www.jb51.cc/php/27714.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

countcountcount数组统计

相关推荐