1. 編譯工具php
(a).ext_skel:這個腳本主要生成了編譯須要的配置以及擴展的基本結構數組
(b).php-config:這個腳本主要是獲取PHP的安裝信息框架
(c).phpize:用於生成configure文件函數
2.編寫擴展的基本步驟工具
a.經過ext目錄下ext_skel腳本生成擴展的基本框架;
./ext_skel --extname=wu
b.修改config.m4配置:設置編譯配置參數、設置擴展的源文件、依賴庫/函數檢查等等;
PHP_ARG_WITH(arg_name,check message,help info): 定義一個--with-feature[=arg]這樣的編譯參數,參數分別爲 參數名、執行./configure是展現信息、執行--help時展現信息 $PHP_參數名:獲取對應的參數值
PHP_ARG_ENABLE(arg_name,check message,help info): 定義一個--enable-feature[=arg]或--disable-feature參 數,--disable-feature等價於--enable-feature=no,這個宏與PHP_ARG_WITH相似,一般狀況下若是配置的參數需 要額外的arg值會使用PHP_ARG_WITH,而若是不須要arg值,只用於開關配置則會使用PHP_ARG_ENABLE。
./configure時輸出結果,其中error將會中斷configure執行 AC_MSG_CHECKING(message) AC_MSG_RESULT(message) AC_MSG_ERROR(message)
PHP_CHECK_LIBRARY(library, function [, action-found [, action-not-found ]]): 檢查依賴的庫中是否存在須要 的function,action-found爲存在時執行的動做,action-not-found爲不存在時執行的動做
c.編寫擴展要實現的功能:按照PHP擴展的格式以及PHP提供的API編寫功能;
#1.註冊全局變量 //php_wu.h #define MYTEST_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(mytest, v) //定義全局變量 ZEND_BEGIN_MODULE_GLOBALS(mytest) zend_long open_cache; HashTable class_table; ZEND_END_MODULE_GLOBALS(mytest) //wu.c ZEND_DECLARE_MODULE_GLOBALS(mytest)
#2.鉤子函數 PHP_MINIT_FUNCTION(mytest){ 這個階段能夠進行內部類的註冊,若是你的擴展提供 了類就能夠在此函數中完成註冊;除了類還能夠在此 函數中註冊擴展定義的常量 } PHP_RINIT_FUNCTION(mytest){ 若是你的擴展須要針對每個請求進行處理則能夠設 置這個函數,如:對請求進行filter } PHP_RSHUTDOWN_FUNCTION(mytest){ 此函數在請求結束時被調用 } PHP_MSHUTDOWN_FUNCTION(mytest){ 模塊關閉階段回調的函數,與module_startup_func對應, 此階段主要能夠進行一些資源的清理 }
#3.自定義函數 PHP_FUNCTION(my_func_1){ 自定義內部函數1 } PHP_FUNCTION(my_func_1){ 自定義內部函數2(帶參) zval *arr; //l(L)整型,L當數據溢出不報錯 //(b)布爾型,(d)浮點型 //s(S)字符串型,其中"s"將參數解析到char*,且須要額外提供一個size_t類型的變量用於獲取字符串長度,「S」爲zend_string //a(A)數組型,o(O)對象型,r資源型,z任意類型 //|: 表示此後的參數爲可選參數,能夠不傳,好比解析規則爲:"al|b",則能夠傳2個或3個參數 //+、* : 用於可變參數,+、*的區別在於 * 表示能夠不傳可變參數,而 + 表示可變參數至少有一個。須要額外提供一個int類型的變量用於獲取具體的數量 if(zend_parse_parameters(ZEND_NUM_ARGS(), "la", &lval, &arr) == FAILURE){ RETURN_FALSE; } } PHP_FUNCTION(my_func_3){ 自定義內部函數3(引用傳參) zval *lval; //必須爲zval zval *obj; //引用參數解析時只能使用"z"解析 if(zend_parse_parameters(ZEND_NUM_ARGS(), "zo", &lval, &obj) == FAILURE){ RETURN_FALSE; } } //參數信息(參數組名,無心義,返回值是否引用,參數個數) ZEND_BEGIN_ARG_INFO_EX(arg_info_3, 0, 0, 2) //pass_by_ref表示是否引用傳參,name爲參數名稱 ZEND_ARG_INFO(pass_by_ref, name) //顯式聲明此參數的類型爲指定類的對象,等價於PHP中這樣聲明:MyClass $obj ZEND_ARG_OBJ_INFO(pass_by_ref, name, classname, allow_null) //顯式聲明此參數類型爲數組,等價於:array $arr ZEND_ARG_ARRAY_INFO(pass_by_ref, name, allow_null) //通用宏,自定義各個字段 ZEND_ARG_TYPE_INFO(pass_by_ref, name, type_hint, allow_null) //聲明爲可變參數 ZEND_ARG_VARIADIC_INFO(pass_by_ref, name) ZEND_END_ARG_INFO() PHP_FUNCITON(my_func_3){ 自定義內部函數4(返回值) //返回布爾型,b:IS_FALSE、IS_TRUE RETURN_BOOL(b) //返回false RETURN_FALSE //返回true RETURN_TRUE //返回NULL RETURN_NULL() //返回整形,l類型:zend_long RETURN_LONG(l) //返回浮點值,d類型:double RETURN_DOUBLE(d) //返回字符串,內部字符串,s類型爲:zend_string * RETURN_STR(s) //返回char *類型的字符串,s類型爲char * RETURN_STRING(s) //返回空字符串 RETURN_EMPTY_STRING() //返回資源,r類型:zend_resource * RETURN_RES(r) //返回數組,r類型:zend_array * RETURN_ARR(r) //返回對象,r類型:zend_object * RETURN_OBJ(r) } const zend_function_entry mytest_functions[] = { PHP_FE(my_func_1,NULL) PHP_FE(my_func_2,NULL) PHP_FE(my_func_3,arg_info_3) PHP_FE(my_func_4,NULL) PHP_FE_END //末尾必須加這個 }; zend_module_entry mytest_module_entry = { STANDARD_MODULE_HEADER, //宏統一設置 "mytest", //模塊名 mytest_functions, //自定義函數數組 PHP_MINIT(mytest), //擴展初始化回調函數 PHP_MSHUTDOWN(mytest), //擴展關閉時回調函數 PHP_RINIT(mytest), //請求開始前回調函數 PHP_RSHUTDOWN(mytest), //請求結束時回調函數 NULL, //PHP_MINFO(mytest),php_info展現的擴展信息處理函數 "1.0.0", STANDARD_MODULE_PROPERTIES //宏統一設置 }; ZEND_GET_MODULE(mytest) //讀取mytest_module_entry結構體
#4.zval操做工具類 //建立(這些宏第一個參數z均爲要設置的zval的指針,後面爲要設置的zend_value) ZVAL_UNDEF(z): 表示zval被銷燬 ZVAL_NULL(z): 設置爲NULL ZVAL_FALSE(z): 設置爲false ZVAL_TRUE(z): 設置爲true ZVAL_BOOL(z, b): 設置爲布爾型,b爲IS_TRUE、IS_FALSE,與上面兩個等價 ZVAL_LONG(z, l): 設置爲整形,l類型爲zend_long,如:zval z; ZVAL_LONG(&z, 88); ZVAL_DOUBLE(z, d): 設置爲浮點型,d類型爲double ZVAL_STR(z, s): 設置字符串,將z的value設置爲s,s類型爲zend_string*,不會增長s的refcount ZVAL_ARR(z, a): 設置爲數組,a類型爲zend_array* ZVAL_OBJ(z, o): 設置爲對象,o類型爲zend_object* ZVAL_RES(z, r): 設置爲資源,r類型爲zend_resource* ZVAL_REF(z, r): 設置爲引用,r類型爲zend_reference* ZVAL_NEW_EMPTY_REF(z): 新建立一個空引用,沒有設置具體引用的value //獲取值及類型 Z_LVAL(zval)、Z_LVAL_P(zval_p): 返回zend_long Z_DVAL(zval)、Z_DVAL_P(zval_p): 返回double Z_STR(zval)、Z_STR_P(zval_p): 返回zend_string* Z_STRVAL(zval)、Z_STRVAL_P(zval_p): 返回char*,即:zend_string->val Z_STRLEN(zval)、Z_STRLEN_P(zval_p): 獲取字符串長度 Z_STRHASH(zval)、Z_STRHASH_P(zval_p): 獲取字符串的哈希值 Z_ARR(zval)、Z_ARR_P(zval_p)、Z_ARRVAL(zval)、Z_ARRVAL_P(zval_p): 返回zend_array* Z_OBJ(zval)、Z_OBJ_P(zval_p): 返回zend_object* Z_OBJCE(zval)、Z_OBJCE_P(zval_p): 返回對象的zend_class_entry* Z_OBJPROP(zval)、Z_OBJPROP_P(zval_p): 獲取對象的成員數組 Z_RES(zval)、Z_RES_P(zval_p): 返回zend_resource* Z_RES_HANDLE(zval)、Z_RES_HANDLE_P(zval_p): 返回資源handle Z_RES_TYPE(zval)、Z_RES_TYPE_P(zval_p): 返回資源type Z_RES_VAL(zval)、Z_RES_VAL_P(zval_p): 返回資源ptr Z_REF(zval)、Z_REF_P(zval_p): 返回zend_reference* Z_REFVAL(zval)、Z_REFVAL_P(zval_p): 返回引用的zval* //類型轉換 convert_to_long(zval *op); convert_to_double(zval *op); convert_to_long_base(zval *op, int base); convert_to_null(zval *op); convert_to_boolean(zval *op); convert_to_array(zval *op); convert_to_object(zval *op); zval_get_long(op):獲取格式化爲long的值,返回值爲zend_long zval_get_double(op):獲取格式化爲double的值,返回值double zval_get_string(op):獲取格式化爲string的值,返回值zend_string * //字符串操做 zend_string_init(const char *str, size_t len, int persistent);建立zend_string zend_string_copy(zend_string *s);字符串複製,只增長引用 zend_string_dup(zend_string *s, int persistent);字符串拷貝,硬拷貝 zend_string_realloc(zend_string *s, size_t len, int persistent);將字符串按len大小從新分配,會減小s的refcount,返回新的字符串 zend_string_extend(zend_string *s, size_t len, int persistent);延長字符串,與zend_string_realloc()相似,不一樣的是len不能小於s的長度 zend_string_refcount(const zend_string *s);獲取字符串refcount zend_string_addref(zend_string *s);增長字符串refcount zend_string_delref(zend_string *s);減小字符串refcount zend_string_release(zend_string *s);釋放字符串,減小refcount,爲0時銷燬 zend_string_free(zend_string *s);銷燬字符串,無論引用計數是否爲0 zend_string_equals(zend_string *s1, zend_string *s2);比較兩個字符串是否相等,區分大小寫 zend_string_equals_ci(s1, s2);比較兩個字符串是否相等,不區分大小寫 //數組操做 ZVAL_NEW_ARR(z): 新分配一個數組,主動分配一個zend_array zend_hash_init(Z_ARRVAL(array), size, NULL, ZVAL_PTR_DTOR, 0);初始化數組 1) key爲zend_string zend_hash_update(ht, key, pData):插入或更新元素,會增長key的refcount zend_hash_add(ht, key, pData):添加元素,與zend_hash_update()相似,不一樣的地方在於若是元素已經存在則不會更新 2) key爲普通字符串:char* zend_hash_str_update(ht, key, len, pData) #define zend_hash_str_add(ht, key, len, pData) 3) key爲數值索引 zend_hash_index_update(ht, h, pData):更新第h個元素 zend_hash_index_add(ht, h, pData):插入元素,h爲數值 zend_hash_find(const HashTable *ht, zend_string *key);根據zend_string key查找數組元素 zend_hash_str_find(const HashTable *ht, const char *key, size_t len);根據普通字符串key查找元素 zend_hash_index_find(const HashTable *ht, zend_ulong h);獲取數值索引元素 zend_hash_exists(const HashTable *ht, zend_string *key);判斷元素是否存在 zend_hash_str_exists(const HashTable *ht, const char *str, size_t len);判斷元素是否存在 zend_hash_index_exists(const HashTable *ht, zend_ulong h);判斷元素是否存在 zend_hash_num_elements(ht):獲取數組元素數 zend_hash_del(HashTable *ht, zend_string *key);刪除key //遍歷 ZEND_HASH_FOREACH_VAL(ht, val) { ... } ZEND_HASH_FOREACH_END(); ZEND_HASH_FOREACH_NUM_KEY(ht, _h):遍歷獲取全部的數值索引 ZEND_HASH_FOREACH_STR_KEY(ht, _key):遍歷獲取全部的key ZEND_HASH_FOREACH_KEY(ht, _h, _key):上面兩個的聚合 ZEND_HASH_FOREACH_NUM_KEY_VAL(ht, _h, _val) :遍歷獲取數值索引key及value ZEND_HASH_FOREACH_STR_KEY_VAL(ht, _key, _val):遍歷獲取key及valu ZEND_HASH_FOREACH_KEY_VAL(ht, _h, _key, _val):上面兩個的聚合 zend_array_destroy(HashTable *ht):銷燬數組
#5.常量 //註冊NULL常量 REGISTER_NULL_CONSTANT(name, flags) //註冊bool常量 REGISTER_BOOL_CONSTANT(name, bval, flags) //註冊整形常量 REGISTER_LONG_CONSTANT(name, lval, flags) //註冊浮點型常量 REGISTER_DOUBLE_CONSTANT(name, dval, flags) //註冊字符串常量,str類型爲char* REGISTER_STRING_CONSTANT(name, str, flags) //註冊字符串常量,截取指定長度,str類型爲char* REGISTER_STRINGL_CONSTANT(name, str, len, flags)
d.生成configure:擴展編寫完成後執行phpize腳本生成configure及其它配置文件;
phpsize
e.編譯&安裝:./configure、make、make install,而後將擴展的.so路徑添加到php.ini中。
./configure make make install