標籤:
定義:
PHP 中的數組實際上是一個有序映射。映射是一種把 values 關聯到 keys 的類型。此類型在很多方面做了最佳化,因此可以把它當成真正的數組,或列表(向量),散列表(是映射的一種實現),字典,集合,棧,隊列以及更多可能性。數組元素的值也可以是另一個數組。樹形結構和多維陣列也是允許的。
這是手冊中對PHP數組的定義,本質上是一種鍵-值對應的關係,算是一種散列表(雜湊表)。
到這裡我不得不說,PHP核心中的神器了 HashTable
HashTable即具有雙向鏈表的優點,PHP中的定義的變數儲存在一個符號表裡,而這個符號表其實就是一個HashTable,它的每一個元素都是一個zval*類型的變數。不僅如此,儲存使用者定義的函數、類、資源等的容器都是以HashTable的形式在核心中實現的。
因此,PHP的數組讀寫都可以在O(1)內完成,這是非常高效的,因此開銷和C++、Java相比也就是hashtable的建立了
我們看一下PHP定義數組
<?php $array = array(); $array["key"] = "value";
在核心中
zval* array; array_init(array); add_assoc_string(array, "key", "value", 1);
這樣就可以了
看一下源碼是怎麼實現
在zend_API.h 檔案中,這是一個宏定義
#define array_init(arg) _array_init((arg), 0 ZEND_FILE_LINE_CC)
接著看,在zend_API.c 檔案中
/* Argument parsing API -- andrei */ZEND_API int _array_init(zval *arg, uint size ZEND_FILE_LINE_DC) /* {{{ */{ ALLOC_HASHTABLE_REL(Z_ARRVAL_P(arg)); _zend_hash_init(Z_ARRVAL_P(arg), size, NULL, ZVAL_PTR_DTOR, 0 ZEND_FILE_LINE_RELAY_CC); Z_TYPE_P(arg) = IS_ARRAY; return SUCCESS;}/* }}} */
再接著看,在zend_alloc.h檔案中
#define ALLOC_HASHTABLE_REL(ht) (ht) = (HashTable *) emalloc_rel(sizeof(HashTable))
再接著看
ZEND_API int _zend_hash_init(HashTable *ht, uint nSize, hash_func_t pHashFunction, dtor_func_t pDestructor, zend_bool persistent ZEND_FILE_LINE_DC){ uint i = 3;//初始化是為1<<3=8 SET_INCONSISTENT(HT_OK);//最大個數為1>>31 = 2^31 =2147483648 if (nSize >= 0x80000000) { /* prevent overflow */ ht->nTableSize = 0x80000000; } else { while ((1U << i) < nSize) { i++; } ht->nTableSize = 1 << i; } ht->nTableMask = 0; /* 0 means that ht->arBuckets is uninitialized */ ht->pDestructor = pDestructor; /* 元素的解構函式(指標) */ ht->arBuckets = (Bucket**)&uninitialized_bucket; ht->pListHead = NULL; /* 頭元素, 用於線性遍曆 */ ht->pListTail = NULL; /* 尾元素, 用於線性遍曆 */ ht->nNumOfElements = 0; /* HashTable中實際元素的個數 */ ht->nNextFreeElement = 0; /* 下個空閑可用位置的數字索引 */ ht->pInternalPointer = NULL; /* 內部位置指標, 會被reset, current這些遍曆函數使用 */ht->persistent = persistent; ht->nApplyCount = 0;/* 迴圈遍曆保護 */ ht->bApplyProtection = 1; return SUCCESS;}
以上是數組初始化可以參考 http://www.laruence.com/2009/08/23/1065.html
然後賦值的過程
zval* val; MAKE_STD_ZVAL(val); ZVAL_STRING(val, "value", 0); zend_hash_add(h, "key", 4, &val, sizeof(zval*), NULL);
核心為我們提供了方便的宏來管理數組
ZEND_API int add_index_long(zval *arg, ulong idx, long n);ZEND_API int add_index_null(zval *arg, ulong idx);ZEND_API int add_index_bool(zval *arg, ulong idx, int b);ZEND_API int add_index_resource(zval *arg, ulong idx, int r);ZEND_API int add_index_double(zval *arg, ulong idx, double d);ZEND_API int add_index_string(zval *arg, ulong idx, const char *str, int duplicate);ZEND_API int add_index_stringl(zval *arg, ulong idx, const char *str, uint length, int duplicate);ZEND_API int add_index_zval(zval *arg, ulong index, zval *value);ZEND_API int add_next_index_long(zval *arg, long n);ZEND_API int add_next_index_null(zval *arg);ZEND_API int add_next_index_bool(zval *arg, int b);ZEND_API int add_next_index_resource(zval *arg, int r);ZEND_API int add_next_index_double(zval *arg, double d);ZEND_API int add_next_index_string(zval *arg, const char *str, int duplicate);ZEND_API int add_next_index_stringl(zval *arg, const char *str, uint length, int duplicate);ZEND_API int add_assoc_long_ex(zval *arg, const char *key, uint key_len, long n);ZEND_API int add_assoc_null_ex(zval *arg, const char *key, uint key_len);ZEND_API int add_assoc_bool_ex(zval *arg, const char *key, uint key_len, int b);ZEND_API int add_assoc_resource_ex(zval *arg, const char *key, uint key_len, int r);ZEND_API int add_assoc_double_ex(zval *arg, const char *key, uint key_len, double d);ZEND_API int add_assoc_string_ex(zval *arg, const char *key, uint key_len, char *str, int duplicate);ZEND_API int add_assoc_stringl_ex(zval *arg, const char *key, uint key_len, char *str, uint length, int duplicate);ZEND_API int add_assoc_zval_ex(zval *arg, const char *key, uint key_len, zval *value);#define add_assoc_long(__arg, __key, __n) add_assoc_long_ex(__arg, __key, strlen(__key)+1, __n)#define add_assoc_null(__arg, __key) add_assoc_null_ex(__arg, __key, strlen(__key) + 1)#define add_assoc_bool(__arg, __key, __b) add_assoc_bool_ex(__arg, __key, strlen(__key)+1, __b)#define add_assoc_resource(__arg, __key, __r) add_assoc_resource_ex(__arg, __key, strlen(__key)+1, __r)#define add_assoc_double(__arg, __key, __d) add_assoc_double_ex(__arg, __key, strlen(__key)+1, __d)#define add_assoc_string(__arg, __key, __str, __duplicate) add_assoc_string_ex(__arg, __key, strlen(__key)+1, __str, __duplicate)#define add_assoc_stringl(__arg, __key, __str, __length, __duplicate) add_assoc_stringl_ex(__arg, __key, strlen(__key)+1, __str, __length, __duplicate)#define add_assoc_zval(__arg, __key, __value) add_assoc_zval_ex(__arg, __key, strlen(__key)+1, __value)
具體實現
$arr[] = NULL; add_next_index_null(arr); $arr[] = 42; add_next_index_long(arr, 42); $arr[] = true; add_next_index_bool(arr, 1); $arr[] = 3.14; add_next_index_double(arr, 3.14); $arr[] = ‘foo‘; add_next_index_string(arr, "foo"); $arr[] = $var; add_next_index_zval(arr, zval); $arr[0] = NULL; add_index_null(arr, 0); $arr[1] = 42; add_index_long(arr, 1, 42); $arr[2] = true; add_index_bool(arr, 2, 1); $arr[3] = 3.14; add_index_double(arr, 3, 3.14); $arr[4] = ‘foo‘; add_index_string(arr, 4, "foo", 1); $arr[5] = $var; add_index_zval(arr, 5, zval); $arr["abc"] = NULL; add_assoc_null(arr, "abc"); $arr["def"] = 42; add_assoc_long(arr, "def", 42); $arr["ghi"] = true; add_assoc_bool(arr, "ghi", 1); $arr["jkl"] = 3.14 add_assoc_double(arr, "jkl", 3.14); $arr["mno"]="foo" add_assoc_string(arr, "mno", "foo", 1"); $arr["pqr"] = $var; add_assoc_zval(arr, "pqr", zval);
擴充中測試
PHP_FUNCTION(array_test1){zval *value;zval *element;char *s="This is a test";char *key="a";MAKE_STD_ZVAL(element);MAKE_STD_ZVAL(value);array_init(value);ZVAL_STRING(element,s,strlen(s));zend_hash_update(value->value.ht,key,strlen(key)+1,(void*)&element,sizeof(zval*),NULL);ZEND_SET_SYMBOL(EG(active_symbol_table),"siren",value); }PHP_FUNCTION(array_test2){ char* str; zval* subarray; array_init(return_value);array_init(subarray); add_next_index_string(return_value, "test", 1); str = estrdup("This is a test"); add_next_index_string(return_value, str, 0); add_assoc_double(return_value, "double", 3.14); add_next_index_string(subarray, "hello", 1); add_assoc_zval(return_value, "xsubarray", subarray); }
深入PHP核心之數組