原創:PHP內核研究:數組的創建

聲明:本文爲斯人原創,全部爲作者一一分析得之,有不對的地方望賜教。
博客地址:PHP技術博客 在CSDN也會同步更新的哦.
歡迎轉載,轉載請註明出處 

PHP之所以發現這麼迅速,有很大原因是因爲數組數據非常好處理,而且它可以存儲其他類型的數據
數組的值存儲在zvalue_value.ht字段中,ht是一個HashTable的數據
有關於HashTable的知識請移步 >> HASH表和變量
我們來詳細說一下數組
PHP裏面所有的數據都離不開zval和HashTable,
一個PHP很簡單的數組初始化,
在C語言裏面實現的卻沒有那麼簡單.
經過簡單分析,找到數組的初始化的opcode
在Zend/zend_vm_execute.h文件中

[c]
static int ZEND_FASTCALL ZEND_INIT_ARRAY_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
zend_op *opline = EX(opline);

array_init(&EX_T(opline->result.u.var).tmp_var); //分配數組內存空間,初始化
if (IS_CV == IS_UNUSED) {
ZEND_VM_NEXT_OPCODE();
#if 0 || IS_CV != IS_UNUSED
} else {
return ZEND_ADD_ARRAY_ELEMENT_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
#endif }
}
[/c]



初始化數組的函數是 array_init
看看它的定義

[c]
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;
}
[/c]

看到沒有,Hash表初始化函數_zend_hash_init
如果對Hash表不清楚 ,猛點這裏>>PHP內核研究第二步:HASH表和變量

下面我們實驗一下,
用擴展創建一個空數組,然後用PHP var_dump;
至於如何擴展PHP這裏不談
關鍵代碼

[c]
PHP_FUNCTION(confirm_siren_compiled)
{
zval *value;
MAKE_STD_ZVAL(value);
array_init(value);
ZEND_SET_SYMBOL(EG(active_symbol_table),"siren",value);

[/c]

PHP執行代碼

[c]
<!--?php dl("siren.so"); confirm_siren_compiled(1); var_dump($siren); ?-->
[/c]

用命令執行 輸出
s# /usr/local/php53/bin/php test.php
array(0) {
}
我們成功創建了一個空數組,如果看過 變量那一章的內容,應該會明白confirm_siren_compiled都做了什麼
不懂的話 猛擊>>PHP內核研究第二步:HASH表和變量

但是創建一個空數組 ,是沒有意義的,如何添加鍵,值?
添加一個元素的關鍵代碼

[c]
PHP_FUNCTION(confirm_siren_compiled)
{
zval *value;
zval *element;
char *s="this is a value";
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);
}
[/c]

執行PHP 結果如下
s# /usr/local/php53/bin/php test.php
array(1) {
["a"]=>
string(15) "this is a value"
}
zend_hash_update只是給數組添加元素的一種方法 ..
還有很多API可以用,

[c]

函數                                                                   說明
add_assoc_long(zval *array, char *key, long n);    添加一個長整型元素。
add_assoc_unset(zval *array, char *key);             添加一個 unset 元素。
add_assoc_bool(zval *array, char *key, int b);       添加一個布爾值。
add_assoc_resource(zval *array, char *key, int r); 添加一個資源。
add_assoc_double(zval *array, char *key, double d); 添加一個浮點值。
add_assoc_string(zval *array, char *key, char *str, int duplicate); 添加一個字符串。duplicate 用於表明這個字符串是否要被複制到 Zend 的內部內存。
add_assoc_stringl(zval *array, char *key, char *str, uint length, int duplicate); 添加一個指定長度的字符串。其餘跟add_assoc_string () 相同。
add_assoc_zval(zval *array, char *key, zval *value); 添加一個 zval 結構。 這在添加另外一個數組、對象或流等數據時會很有用
add_index_long(zval *array, uint idx, long n); 添加一個長整型元素。
add_index_unset(zval *array, uint idx); 添加一個 unset 元素。
add_index_bool(zval *array, uint idx, int b); 添加一個布爾值。
add_index_resource(zval *array, uint idx, int r); 添加一個資源。
add_index_double(zval *array, uint idx, double d); 添加一個浮點值。
add_index_string(zval *array, uint idx, char *str, int duplicate); 添加一個字符串。duplicate 用於表明這個字符串是否要被複制到 Zend 的內部內存。
add_index_stringl(zval *array, uint idx, char *str, uint length, int duplicate); 添加一個指定長度的字符串。其餘跟add_index_string () 相同。
add_index_zval(zval *array, uint idx, zval *value); 添加一個 zval 結構。 這在添加另外一個數組、對象或流等數據時會很有用。
add_next_index_long(zval *array, long n); 添加一個長整型元素。
add_next_index_unset(zval *array); 添加一個 unset 元素。
add_next_index_bool(zval *array, int b); 添加一個布爾值。
add_next_index_resource(zval *array, int r); 添加一個資源。
add_next_index_double(zval *array, double d); 添加一個浮點值。
add_next_index_string(zval *array, char *str, int duplicate); 添加一個字符串。duplicate 用於表明這個字符串是否要被複制到 Zend 的內部內存。
add_next_index_stringl(zval *array, char *str, uint length, int duplicate); 添加一個指定長度的字符串。其餘跟add_next_index_string () 相同。
add_next_index_zval(zval *array, zval *value); 添加一個 zval 結構。 這在添加另外一個數組、對象或流等數據時會很有用。
[/c]


具體使用方法很簡單,看參數名稱就知道方法了,自己試驗吧...


發佈了132 篇原創文章 · 獲贊 13 · 訪問量 70萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章