當 PHP 腳本與擴展互相交換數據時,我們還需要做一件很重要的事情,那就是創建變量。這一小節將會展示如何處理那些 PHP 腳本所支持的變量類型。
概述
要創建一個能夠被 PHP 腳本所訪問的“外部變量”,我們只需先創建一個 zval 容器,然后對這個 zval 結構進行必要的填充,最后再把它引入到 Zend 的內部符號表中就可以了。而且幾乎所有變量的創建基本上都是這幾個步驟:
zval *new_variable;
/*?申請并初始化一個新的的 zval 容器?*/
php是開源的嗎、MAKE_STD_ZVAL(new_variable);
/* 設置變量的類型和內容,見下 */
/* 將名為 “new_variable_name” 變量引入符號表 */
ZEND_SET_SYMBOL(EG(active_symbol_table), “new_variable_name”, new_variable);
/* 現在就可以在腳本中用 $new_variable_name 來訪問這個變量了 */
宏 MAKE_STD_ZVAL 通過 ALLOC_ZVAL 來申請一個新的 zval 容器的內存空間并調用 INIT_ZVAL(查看 PHP4/5 的源代碼可知此處為原文筆誤,實際上應為 INIT_PZVAL,下同。譯注)將其初始化。在當前的 Zend Engine 中,INIT_ZVAL 所負責的初始化工作除了將 zval 容器的引用計數(refcount)置為 1 之外,還會把引用標識也清除(即把 is_ref? 也置為 0)。而且在以后的 Zend Engine 中還可能會繼續擴展這個 INIT_ZVAL 宏操作,因此我們推薦您使用 MAKE_STD_ZVAL 而非簡單使用一個 ALLOC_ZVAL 來完成一個變量的創建工作。當然,如果您是想優化一下速度(或者是不想明確地初始化這個 zval 容器),那還是可以只用 ALLOC_ZVAL 來搞定的。不過我們并不推薦這么做,因為這將不能保證數據的完整性。
php elseif、ZEND_SET_SYMBOL 宏負責將我們新建的變量引入 Zend 內部的符號表。這個宏會首先檢查一下這個變量是否已經存在于符號表中,如果已經存在則將其轉換為一個引用變量(同時會自動銷毀原有的
zval 容器)。事實上這個方法經常用在某些速度要求并不苛刻但希望能少用一些內存的情況下。
您可能注意到了
ZEND_SET_SYMBOL 是通過宏 EG 來訪問 Zend 執行器(executor)的全局結構的。特別的,如果你使用的是
EG(active_symbol_table),那你就可以訪問到當前的活動符號表,從而可以處理一些全局或局部變量。其中局部變量可能會依不同的函數而有所不同。.
當然,要是你很在意程序的運行速度并且不在乎那一點點內存的話,那你可以跳過對相同名字變量存在性的檢查而直接使用
php api框架、zend_hash_update() 函數強行將這個名字的變量插入符號表。
zval *new_variable;
/*?申請并初始化一個新的的 zval 容器?*/
MAKE_STD_ZVAL(new_variable);
/* 設置變量的類型和內容,見下 */
/* 將名為 “new_variable_name” 變量引入符號表 */
php高級開發。zend_hash_update(
EG(active_symbol_table),
”new_variable_name”,
strlen(”new_variable_name”) + 1,
&new_variable,
sizeof(zval *),
php 消息隊列?NULL
);
實際上這段代碼也是很多擴展使用的標準方法。
上面這段代碼所產生的變量是局部變量,作用范圍跟調用函數的上下文相關。如果你想創建一個全局變量那也很簡單,方法還是老方法,只需換個符號表就可以了。
zval *new_variable;
/*?申請并初始化一個新的的 zval 容器?*/
php標準。MAKE_STD_ZVAL(new_variable);
/* 設置變量的類型和內容,見下 */
/* 將名為 “new_variable_name” 變量引入全局符號表 */
ZEND_SET_SYMBOL(&EG(symbol_table), “new_variable_name”, new_variable);
注意,現在宏
ZEND_SET_SYMBOL 使用的符號表是全局符號表
php擴展模塊開發?EG(symbol_table)。另外,
active_symbol_table 是一個指針,而
symbol_table 卻不是。這就是我們為什么分別使用
EG(active_symbol_table) 和
&EG(symbol_table) 的原因 -
ZEND_SET_SYMBOL 需要一個指針作為其參數。
php laravel?當然,你同樣也可以強行更新這個符號表:
zval *new_variable;
/*?申請并初始化一個新的的 zval 容器?*/
MAKE_STD_ZVAL(new_variable);
/* 設置變量的類型和內容,見下 */
/* 將名為 “new_variable_name” 變量引入全局符號表 */
php內核。zend_hash_update(
&EG(symbol_table),
”new_variable_name”,
strlen(”new_variable_name”) + 1,
&new_variable,
sizeof(zval *),
php api、NULL
);
例 3.9 “創建不同作用域的變量”向我們展示了創建一個局部變量(local_variable)和一個全局變量(global_variable)的過程。.
注意:你可能會發現在 PHP 函數里似乎還不能直接訪問這個全局變量(global_variable),因為你在使用前還必須使用
global $global_variable; 聲明一下。
例3.9 創建不同作用域的變量
php寫api接口實例、ZEND_FUNCTION(variable_creation)
{
zval *new_var1, *new_var2;
MAKE_STD_ZVAL(new_var1);
MAKE_STD_ZVAL(new_var2);
ZVAL_LONG(new_var1, 10);
php調用第三方api接口,ZVAL_LONG(new_var2, 5);
ZEND_SET_SYMBOL(EG(active_symbol_table), “local_variable”, new_var1);
ZEND_SET_SYMBOL(&EG(symbol_table), “global_variable”, new_var2);
RETURN_NULL();
}
長整型(整數)
php教程,現在讓我們以長整型變量起點,了解一下如何為一個變量賦值。PHP 中的整數全部是長整型,其值的存儲方法也是非常簡單的。看一下我們前面討論過的 zval.value 容器的結構你就會明白,所有的長整型數據都是直接保存在這個聯合中的 lval 字段,相應的數據類型(type 字段)為
IS_LONG(見
例3.10 “長整型變量的創建”)。
例3.10 長整型變量的創建
zval *new_long;
MAKE_STD_ZVAL(new_long);
php和html混合編程?new_long->type = IS_LONG;
new_long->value.lval = 10;
或者你也可以直接使用
ZVAL_LONG 宏:
zval *new_long;
MAKE_STD_ZVAL(new_long);
php7.4?ZVAL_LONG(new_long, 10);
雙精度型(浮點數)
PHP 中的浮點數都是雙精度型,存儲方法和整型差不多,也很簡單。它的值是直接放在聯合中的 dval 字段,對應數據類型為
IS_DOUBLE。
zval *new_double;
MAKE_STD_ZVAL(new_double);
php框架?new_double->type = IS_DOUBLE;
new_double->value.dval = 3.45;
同樣你也可以直接使用宏
ZVAL_DOUBLE:
zval *new_double;
MAKE_STD_ZVAL(new_double);
php實現內核插件架構。ZVAL_DOUBLE(new_double, 3.45);
字符串
字符串的存儲可能會稍費點事。字符串的值是保存在
zval.value 容器中的
str 結構里面,相應的數據類型為
IS_STRING。不過需要注意的是,前面我們已經提到過,所有與 Zend 內部數據結構相關的字符串都必須使用 Zend 自己的內存管理函數來申請空間。這樣一來,就不能使用那些靜態字符串(因為這種字符串的內存空間是編譯器預先分配的)或通過標準函數(比如
深入理解php內核pdf?malloc() 等函數)來申請空間的字符串。
zval *new_string;
char *string_contents = “This is a new string variable”;
MAKE_STD_ZVAL(new_string);
new_string->type = IS_STRING;
new_string->value.str.len = strlen(string_contents);
new_string->value.str.val = estrdup(string_contents);
請注意,在這我們使用了
estrdup() 函數。當然我們仍可直接使用一個預定義宏
ZVAL_STRING 來完成這項工作:
zval *new_string;
char *string_contents = “This is a new string variable”;
MAKE_STD_ZVAL(new_string);
ZVAL_STRING(new_string, string_contents, 1);
ZVAL_STRING 宏的第三個參數指明了該字符串是否需要被復制(使用
estrdup() 函數)。值為 1 將導致該字符串被復制,為 0 時則僅僅是簡單地將其指向該變量的值容器(即字符串地址,譯注)。這項特性將會在你僅僅需要創建一個變量并將其指向一個已經由 Zend 內部數據內存時變得很有用。
如果你想在某一位置截取該字符串或已經知道了這個字符串的長度,那么可以使用宏
ZVAL_STRINGL(zval, string, length, duplicate) 來完成這項工作。這個函數會額外需要一個表明該字符串長度地參數。這個宏不但速度上要比
ZVAL_STRING 快,而且還是二進制安全的。
如果想創建一個空字符串,那么將其長度置 0 并且把
empty_string 作為字符串的內容即可:
new_string->type = IS_STRING;
new_string->value.str.len = 0;
new_string->value.str.val = empty_string;
當然,我們也專門為您準備了一個相應的宏
ZVAL_EMPTY_STRING來搞定這個步驟:
MAKE_STD_ZVAL(new_string);
ZVAL_EMPTY_STRING(new_string);
布爾類型
布爾類型變量的創建跟長整型差不多,只是數據類型為
IS_BOOL,并且字段
lval 所允許的值只能為 0 和 1:
zval *new_bool;
MAKE_STD_ZVAL(new_bool);
new_bool->type = IS_BOOL;
new_bool->value.lval = 1;
也可以使用宏
ZVAL_BOOL (需要另外指定一個值)來完成這件事情,或者干脆直接使用
ZVAL_TRUE 或
ZVAL_FALSE 直接將其值設定為
TRUE 或
FALSE。
數組
數組在 Zend 內部是用哈希表(HashTable)來存儲的,這個哈希表可以使用一系列的
zend_hash_*() 函數來訪問。因此我們在創建一個數組時必須先創建一個哈希表,然后再將其保存在
zval.value 容器的
ht 字段中。
不過針對數組的創建我們現在另有一套非常方便 API 可供使用。為了創建一個數組,我們可先調用一下
array_init() 函數:.
zval *new_array;
MAKE_STD_ZVAL(new_array);
array_init(new_array);
array_init() 函數總是返回
SUCCESS。
要給數組增加一個元素,根據實際需要,我們有 N 個函數可供調用。“表3.8 用于關聯數組的 API”、“表3.9 用于索引數組的 API 第一部分”和“表3.10 用于索引數組的 API 第二部分”有這些函數的說明。所有這些函數在調用成功時返回 SUCCESS,在調用失敗時返回 FAILURE。
表3.8 用于關聯數組的 API
函數
說明
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 結構。 這在添加另外一個數組、對象或流等數據時會很有用。
表3.9 用于索引數組的 API 第一部分
函數
說明
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 結構。 這在添加另外一個數組、對象或流等數據時會很有用。
表3.10 用于索引數組的 API 第二部分
函數
說明
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 結構。 這在添加另外一個數組、對象或流等數據時會很有用。
所有這些函數都是對 Zend 內部 hash API 的一種友好抽象。因此,若你愿意,你大可直接使用那些 hash API 進行操作。比方說,假如你已經有了一個 zval 容器并想把它插入到一個數組,那么你就可以直接使用
zend_hash_update() 來把它添加到一個關聯數組(例3.11 給關聯數組添加一個元素)或索引數組(例3.12 給索引數組添加一個元素)。
例3.11 給關聯數組添加一個元素
zval *new_array, *new_element;
char *key = “element_key”;
MAKE_STD_ZVAL(new_array);
MAKE_STD_ZVAL(new_element);
array_init(new_array);
ZVAL_LONG(new_element, 10);
if(zend_hash_update(new_array->value.ht, key, strlen(key) + 1, (void *)&new_element, sizeof(zval *), NULL) == FAILURE)
{
// do error handling here
}
例3.12 給索引數組添加一個元素
zval *new_array, *new_element;
int key = 2;
MAKE_STD_ZVAL(new_array);
MAKE_STD_ZVAL(new_element);
array_init(new_array);
ZVAL_LONG(new_element, 10);
if(zend_hash_index_update(new_array->value.ht, key, (void *)&new_element, sizeof(zval *), NULL) == FAILURE)
{
// do error handling here
}
如果還想模擬下
add_next_index_*() ,那可以這么做:
zend_hash_next_index_insert(ht, zval **new_element, sizeof(zval *), NULL)
注意:如果要從函數里面返回一個數組,那就必須首先對預定義變量 return_value (return_value 是我們導出函數中的一個預定義參數,用來存儲返回值)使用一下
array_init() 函數。不過倒不必對其使用 MAKE_STD_ZVAL 。
提示:為了避免一遍又一遍地書寫 new_array->value.ht,我們可以用
HASH_OF(new_array) 來代替。而且出于兼容性和風格上的考慮,我們也推薦您這么做。
對象
既然對象可以被轉換成數組(反之亦然),那么你可能已經猜到了兩者應該具有很多相似之處。實際上,對象就是使用類似的函數進行操作的,所不同的是創建它們時所用的 API。
我們可以調用
object_init() 函數來初始化一個對象:
zval *new_object;
MAKE_STD_ZVAL(new_object);
if(object_init(new_object) != SUCCESS)
{
// do error handling here
}
可以使用“表3.11 用于創建對象的 API”來給對象添加一些成員。
表3.11 用于創建對象的 API
函數
說明
add_property_long(zval *object, char *key, long l);
添加一個長整型類型的屬性值。
add_property_unset(zval *object, char *key);
添加一個 unset 類型的屬性值。
add_property_bool(zval *object, char *key, int b);
添加一個布爾類型的屬性值。
add_property_resource(zval *object, char *key, long r);
添加一個資源類型的屬性值。
add_property_double(zval *object, char *key, double d);
添加一個浮點類型的屬性值。
add_property_string(zval *object, char *key, char *str, int duplicate);
添加一個字符串類型的屬性值。
add_property_stringl(zval *object, char *key, char *str, uint length, int duplicate);
添加一個指定長度的字符串類型的屬性值,速度要比 add_property_string() 函數快,而且是二進制安全的。
add_property_zval(zval *obect, char *key, zval *container);
添加一個 zval 結構的屬性值。 這在添加另外一個數組、對象等數據時會很有用。
資源
資源是 PHP 中一種比較特殊的數據類型。“資源”這個詞其實并不特指某些特殊類型的數據,事實上,它指的是一種可以維護任何類型數據信息方法的抽象。所有的資源均保存在一個 Zend 內部的資源列表當中。列表中的每份資源都有一個指向可以表明其種類的類型定義的指針。Zend 在內部統一管理所有對資源的引用。直接訪問一個資源是不大可能的,你只能通過提供的 API 來對其進行操作。某個資源一旦失去引用,那就會觸發調用相應的析構函數。
舉例來說,數據庫連接和文件描述符就是一種資源。MySQL 模塊中就有其“標準”實現。當然其他模塊(比如 Oracle 模塊)也都用到了資源。
注意:
實際上,一個資源可以指向函數中任何一種你所感興趣的數據(比如指向一個結構等等)。并且用戶也只能通過某個資源變量來將資源信息傳遞給相應的函數。
要想創建一個資源你必須先注冊一個這個資源的析構函數。這是因為Zend 需要了解當你把某些數據存到一個資源里后,如果不再需要這份資源時該如何將其釋放。這個析構函數會在釋放資源(無論是手工釋放還是自動釋放)時被 Zend 依次調用。析構函數注冊后,Zend 會返回一個此種
資源類型句柄。這個句柄會在以后任何訪問此種類型的資源的時候被用到,而且這個句柄絕大部分時間都保存在擴展的全局變量里面。這里你不需要擔心線程安全方面的問題,因為你只是需要在模塊初始化注冊一次就行了。
下面是這個用于注冊資源析構函數的 Zend 函數定義:
ZEND_API int zend_register_list_destructors_ex(rsrc_dtor_func_t ld, rsrc_dtor_func_t pld, char *type_name, int module_number);
你或許已經注意到了,在該函數中我們需要提供兩種不同的資源析構函數:一種是普通資源的析構函數句柄,一種是持久化資源的析構函數句柄。持久化資源一般用于諸如數據庫連接等這類情況。在注冊資源時,這兩個析構函數至少得提供一個,另外一個析構函數可簡單地設為 NULL。
zend_register_list_destructors_ex() 接受以下幾個參數:
ld
普通資源的析構函數。
ld
持久化資源的析構函數。
type_name
為你的資源指定一個名稱。在 PHP 內部為某個資源類型起個名字這是個好習慣(當然名字不能重復)。用戶調用 var_dump($resource) 時就可取得該資源的名稱。
module_number
這個參數在你模塊的 PHP_MINIT_FUNCTION 函數中會自動定義,因此你大可將其忽略。
返回值是表示該
資源類型的具有唯一性的整數標識符,即
資源類型句柄。
資源(不論是不是持久化資源)的析構函數都必須具有以下的函數原型:
void resource_destruction_handler(zend_rsrc_list_entry *rsrc TSRMLS_DC);
參數
rsrc 指向一個 zend_rsrc_list_entry 結構:
typedef struct _zend_rsrc_list_entry {
void *ptr;
int type;
int refcount;
} zend_rsrc_list_entry;
成員
void *ptr 才真正指向你的資源。
現在我們就知道該怎么開始了。我們先定義一個將要注冊到 Zend 內部的資源類型 my_resource,這個類型的結構很簡單,只有兩個整數成員:
typedef struct {
int resource_link;
int resource_type;
} my_resource;
接著我們再定義一下這種資源的析構函數。這個析構函數大致上是以下這個樣子:
void my_destruction_handler(zend_rsrc_list_entry *rsrc TSRMLS_DC) {
// 先將無類型指針轉換為我們的資源類型指針
my_resource *my_rsrc = (my_resource *) rsrc->ptr;
// 現在我們就可以隨意處理這些資源了:像關閉文件、釋放內存等等。
// 當然也不要忘了釋放資源本身所占用的內存!
do_whatever_needs_to_be_done_with_the_resource(my_rsrc);
}
注意:
有一個很重要的事情必須要提一下:如果你的資源是一個比較復雜的結構,比如包含有你在運行時所申請內存的指針等,那你就必須在釋放資源本身前
先釋放它們!
OK。現在我們定義了
我們的資源是什么樣子;
我們資源的析構函數是什么樣子。
那么,我們還需要做哪些工作呢?我們還需要:
創建一個在整個擴展范圍內有效的全局變量用于保存資源類型句柄,這樣就可以在每個需要它的函數中都能訪問到它;
給我們的資源類型定義一個名稱;
完成前面定義的資源析構函數;
最后注冊這個析構函數。
// 在你擴展的某個地方定義一個表示資源類型的變量
static int le_myresource;
// 給我們的資源起個名字是個很不錯的習慣
#define le_myresource_name ?”My type of resource”
[…]
// 現在完成我們資源的析構函數
void my_destruction_handler(zend_rsrc_list_entry *rsrc TSRMLS_DC) {
my_resource *my_rsrc = (my_resource *) rsrc->ptr;
do_whatever_needs_to_be_done_with_the_resource(my_rsrc);
}
[…]
PHP_MINIT_FUNCTION(my_extension) {
//?注意 ‘module_number’ 已經在 PHP_MINIT_FUNCTION()?函數中被定義過了
le_myresource = zend_register_list_destructors_ex(my_destruction_handler, NULL, le_myresource_name, module_number);
// 然后你可以在這里注冊一些附加資源、初始化全局變量、常量等等。
}
注冊完這種資源的析構函數后,要真正注冊一個資源(實例),我們可以使用
zend_register_resource() 函數或使用
ZEND_REGISTER_RESOURE() 宏。這兩個的定義可以在 zend_list.h 中找到。盡管兩者的參數定義都是一一對應的,但使用宏通常可以得到更好的前向兼容性:
int ZEND_REGISTER_RESOURCE(zval *rsrc_result, void *rsrc_pointer, int rsrc_type);
rsrc_result
這是一個初始化過 zval * 容器。
rsrc_pointer
指向所保存的資源。
rsrc_type
這個參數就是你在注冊函數析構函數時返回的資源類型句柄。對上面的代碼來說就是le_myresource le_myresource。
返回值就是表示這個資源(實例)的具有唯一性的整數。
那么在我們注冊這個資源(實例)時究竟發生了什么事呢?函數會從 Zend 內部某個列表取得一個空閑空間,然后將資源指針及類型保存到這個空間。最后這個空閑空間的索引被簡單地保存在給定的
zval * 容器里面:
rsrc_id = zend_list_insert(rsrc_pointer, rsrc_type);
if (rsrc_result) {
rsrc_result->value.lval = rsrc_id;
rsrc_result->type = IS_RESOURCE;
}
return rsrc_id;
返回值
rsrc_id 就唯一性地標識了我們新注冊得到的那個資源。你可以使用宏
RETURN_RESOURE 來將其返回給用戶:
RETURN_RESOURCE(rsrc_id)
注意:
如果你想立刻把這個資源返回給用戶,那你就應該把 return_value 作為那個 zval * 容器。這也是我們推薦的一種編程實踐。
Zend 引擎從現在就會開始跟蹤所有對這個資源的引用。一旦對這個資源的引用全都不存在了,那么你在前面為這個資源所注冊的析構函數就會被調用。這樣做的好處就是你不用擔心會在你的模塊里面引入內存泄漏-你只需要把你調用腳本中所有需要分配的內存都注冊成資源即可。這樣一來,一旦腳本認為不再需要它們的時候,Zend 就會找到它們然后再通知你(這就是 callback,譯注)。
現在用戶已經通過在某處傳入到你函數的參數拿到了他的資源。
zval * 容器中的
value.lval 包含了你資源的標識符,然后他就可以宏
ZEND_FETCH_RESOURCE 來獲取資源了:
ZEND_FETCH_RESOURCE(rsrc, rsrc_type, rsrc_id, default_rsrc_id, resource_type_name, resource_type)
rsrc
這個指針將指向你前面已經聲明過的資源。
rsrc_type
這個參數用以表明你你想要把前面參數的那個指針轉換為何種類型。比如 myresource * 等等。
rsrc_id
這個是用戶傳進你函數的那個 zval *container 的地址。 假如給出的是 zval *z_resource ,那么此處就應該是 &z_resource。
default_rsrc_id
這個參數表明假如沒有取到資源時默認指定的資源標識符。通常為 -1。
resource_type_name
所請求的資源類型資源類型名稱。當不能找到資源時,就用這個字符串去填充系統由于維護而拋出的錯誤信息。
resource_type
這個可以取回在注冊資源析構函數時返回的資源類型。在本例就是 le_myresource。
這個宏沒有返回值。這對開發人員可能會方便了點。不過還是要注意添加 TSRM 參數和確認一下是否取回了資源。如果在接收資源時出現了問題,那它就會拋出一個警告信息并且會立刻從當前函數返回,其返回值為 NULL。
如果想從列表強行刪除一個資源,可以使用
zend_list_delete() 函數。當然也可以強行增加引用計數,如果你知道你正在創建一個指向已分配內存資源的引用(比如說你可能想重用一個默認的數據庫連接)。對于這種情況你可以使用函數
zend_list_addref() 。想要查找一個已分配內存的資源,請使用
zend_list_find() 函數。關于這些操作的完整 API 請參見
zend_list.h。
自動創建全局變量的宏
作為我們早期所談論的一些宏的補充,還有一些宏可以讓我們很方便的創建全局變量。了解了它們,我們在引入一些全局標識時就會感覺很爽,不過這個習慣可能會不太好。在“表3.12 創建全局變量的宏”中描述了完成這些任務所用到的正確的宏。它們不需要申請任何 zval 容器,你只需簡單地提供一個變量名和其值即可。
表3.12 創建全局變量的宏
宏
說明
SET_VAR_STRING(name, value)
新建一個字符串變量。
SET_VAR_STRINGL(name, value, length)
新建一個指定長度的字符串變量。這個宏要比 SET_VAR_STRING 快而且還是二進制安全的。
SET_VAR_LONG(name, value)
新建一個長整型變量。
SET_VAR_DOUBLE(name, value)
新建一個雙精度變量。
創建常量
Zend 支持創建真正的常量。訪問常量時不需要
$ 前綴,而且常量是全局有效的。比如
TRUE 和
FALSE 這兩個常量。
要想創建一個常量,你可以使用“表3.13 創建常量的宏”中所列舉的宏來完成這項工作。所有的宏在創建常量時都必須指定一個名稱和值。
你還可以為常量指定一個特別的標識:
CONST_CS - 這個常量的名稱是大小寫敏感的;
CONST_PERSISTENT - 這個常量是持久化的。換句話說,當攜帶這個常量的進程關閉時這個常量在剩下的請求中還依然有效,并不會被“遺忘”。
可以使用二進制的“或(OR)”操作來使用其中的一個或兩個標識:
// 注冊一個長整型常量
REGISTER_LONG_CONSTANT(”NEW_MEANINGFUL_CONSTANT”, 324, CONST_CS |
CONST_PERSISTENT);
我們提供有兩種不同類型的宏,分別是
REGISTER_*_CONSTANT 和
REGISTER_MAIN_*_CONSTANT。第一種類型在創建常量時只會綁定到當前模塊。一旦注冊這個模塊的常量從內存中卸載,那么這個常量也就會隨即消逝。第二種類型創建的變量將會獨立于該模塊,始終保存在符號表中。
表3.13?創建常量的宏
宏
說明
REGISTER_LONG_CONSTANT(name, value, flags) REGISTER_MAIN_LONG_CONSTANT(name, value, flags)
新建一個長整型常量。
REGISTER_DOUBLE_CONSTANT(name, value, flags) REGISTER_MAIN_DOUBLE_CONSTANT(name, value, flags)
新建一個雙精度型常量。
REGISTER_STRING_CONSTANT(name, value, flags) REGISTER_MAIN_STRING_CONSTANT(name, value, flags)
新建一個字符串常量。給定的字符串的空間必須在Zend 內部內存。
REGISTER_STRINGL_CONSTANT(name, value, length, flags) REGISTER_MAIN_STRINGL_CONSTANT(name, value, length, flags)
新建一個指定長度的字符串常量。同樣,這個給定的字符串的空間也必須在Zend 內部內存。
版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。
工作时间:8:00-18:00
客服电话
电子邮件
admin@qq.com
扫码二维码
获取最新动态