所有PHP擴充遵循一個共同的結構
1、標頭檔包含(包括所有需要的宏、API)2、C聲明匯出函數3、聲明Zend函數塊
一、標頭檔包含通過ext_seketon建立的擴充,預設都會建立一個php_extname.h的標頭檔。其中包含了php.h,該檔案匯入Zend基本的宏和API。
二、聲明匯出函數ZEND_FUNCTION(my_function),提供PHP中調用的函數。展開此宏:void zif_my_function(INTERNAL_FUNCTION_PARAMETERS)void zif_my_function(int ht, zval *return_value, zval *this_ptr, int return_value_users, zend_executor_globals *executor_globals);參數的作用:
| 參數 |
描述 |
| ht |
接收的參數個數。考慮向後相容,使用ZEND_NUM_ARGS()來代替ht |
| return_value |
傳遞到PHP介面的傳回值。 |
| this_ptr |
如果這個函數是對象中的方法,this_ptr返回當前對象 |
| return_value_used |
標誌最終這個函數返回到PHP介面中是否被使用。 |
| executor_globals |
指向zend引擎的全域設定。 |
三、聲明Zend函數塊建立zend_function_entry數組,提供給ZEND作為PHP的介面。
typedef struct _zend_function_entry { char *fname; void (*handler)(INTERNAL_FUNCTION_PARAMETERS); unsigned char *func_arg_types;} zend_function_entry;
| 參數 |
描述 |
| fname |
提供給PHP中調用的函數名。例如mysql_connect |
| handler |
負責處理這個介面函數的指標。 |
| func_arg_types |
標記參數。可以設定為NULL |
static const zend_function_entry mysql_functions[] = { PHP_FE(mysql_connect, arginfo_mysql_connect) PHP_FE(mysql_pconnect, arginfo_mysql_pconnect) PHP_FE(mysql_close, arginfo__optional_mysql_link) PHP_FE(mysql_select_db, arginfo_mysql_select_db) {NULL, NULL, NULL}}上述是mysql擴充中定義的zend_function_entry的部分。其中{NULL, NULL, NULL}標誌數組的結束
四、聲明Zend模組擴充結構此塊資訊必須儲存在zend_module_entry結構中,包含模組的必要資訊。例如,初始化模組函數指標,模組的名稱,版本資訊等。
struct _zend_module_entry { unsigned short size; unsigned int zend_api; unsigned char zend_debug; unsigned char zts; char *name; zend_function_entry *functions; int (*module_startup_func)(INIT_FUNC_ARGS); int (*module_shutdown_func)(SHUTDOWN_FUNC_ARGS); int (*request_startup_func)(INIT_FUNC_ARGS); int (*request_shutdown_func)(SHUTDOWN_FUNC_ARGS); void (*info_func)(ZEND_MODULE_INFO_FUNC_ARGS); char *version; [more]};
typedef struct _zend_module_entry zend_module_entry;
| 參數 |
描述 |
| size, zend_api, zend_debug and zts |
通常使用STANDARD_MODULE_HEADER來填充, |
| name |
擴充的名稱 |
| functions |
指向zend_functions_entry指標 |
| module_startup_func |
模組初始化時被調用的函數指標。用來放一些初始化步驟。初始化過程中出現故障返回FAILURE,成功返回SUCCESS。聲明一個初始化函數使用ZEND_MINIT |
| module_shutdown_func |
模組被關閉時調用的函數指標,同來用來做一次性的析構步驟。如釋放資源。 成功返回SUCESS,失敗返回FAILURE,未使用返回NULL。聲明使用ZEND_MSHUTDOWN |
| request_startup_func |
每處理一次請求前調用此函數。成功SUCESS,失敗FAILURE,未使用返回NULL。聲明使用ZEND_RINIT。 從WEB來解釋,就是每次請求調用此函數。 |
| request_startup_func |
每處理一次請求前後調用此函數。成功SUCESS,失敗FAILURE,未使用返回NULL。聲明使用ZEND_RINIT。 |
| request_shutdown_func |
每處理一次請求結束後調用此函數。成功SUCESS,失敗FAILURE,未使用返回NULL。聲明使用ZEND_RSHUTDOWN。 |
| info_func |
當調用phpinfo()時列印出的關於此擴充的資訊。 這個資訊就是由此函數來輸出的。 聲明使用ZEND_MINFO |
| version |
擴充的字串版本號碼。若無版本號碼,可以使用NO_VERSION_YET |
| [more] |
多餘不重要的參數,可以使用宏STANDARD_MODULE_PROPERTIES_EX或STANDARD_MODULE_PROPERTIES |
zend_module_entry firstmod_module_entry ={ STANDARD_MODULE_HEADER, "New Module", firstmod_functions, NULL, NULL, NULL, NULL, NULL, NO_VERSION_YET, STANDARD_MODULE_PROPERTIES,};這是一個最基本的模組結構,模組名“New Module”,函數列表為firstmod_functions,未設定startup、shutdown函數
下面是名為test的PHP擴充的檔案,通過上面的介紹,對比下面的代碼,就會比較清晰的理解PHP擴充開發的步驟。
#ifdef HAVE_CONFIG_H#include "config.h"#endif/*包含ZEND提供的API、宏和基本的PHP內建函數,例如php_trim*/#include "php.h"#include "php_ini.h"#include "ext/standard/info.h"#include "php_test.h"/* 開啟模組中的全域變數 */ZEND_DECLARE_MODULE_GLOBALS(test)/* True global resources - no need for thread safety here */static int le_test;/* * 聲明函數數組,提供給PHP使用*/const zend_function_entry test_functions[] = { PHP_FE(my_function, NULL) /* For testing, remove later. */ PHP_FE_END /* Must be the last line in test_functions[] */};/* }}} *//* 模組結構,聲明了startup\shutdown、模組名及phpinfo列印時的函數*/zend_module_entry test_module_entry = {#if ZEND_MODULE_API_NO >= 20010901 STANDARD_MODULE_HEADER,#endif "test", test_functions, PHP_MINIT(test), PHP_MSHUTDOWN(test), PHP_RINIT(test), /* Replace with NULL if there's nothing to do at request start */ PHP_RSHUTDOWN(test), /* Replace with NULL if there's nothing to do at request end */ PHP_MINFO(test),#if ZEND_MODULE_API_NO >= 20010901 "0.1", /* Replace with version number for your extension */#endif STANDARD_MODULE_PROPERTIES};#ifdef COMPILE_DL_TESTZEND_GET_MODULE(test)#endif/* 從php.ini設定檔中讀取配置資訊 */PHP_INI_BEGIN() STD_PHP_INI_ENTRY("test.global_value", "42", PHP_INI_ALL, OnUpdateLong, global_value, zend_test_globals, test_globals) STD_PHP_INI_ENTRY("test.global_string", "foobar", PHP_INI_ALL, OnUpdateString, global_string, zend_test_globals, test_globals)PHP_INI_END()/* 初始化全域變數預設值 */static void php_test_init_globals(zend_test_globals *test_globals){ test_globals->global_value = 0; test_globals->global_string = NULL;}/* 模組第一次載入時被調用*/PHP_MINIT_FUNCTION(test){ /* 註冊全域變數 */ REGISTER_INI_ENTRIES(); return SUCCESS;}/* 模組關閉時調用*/PHP_MSHUTDOWN_FUNCTION(test){ /* 釋放全域變數 */ UNREGISTER_INI_ENTRIES(); return SUCCESS;}/* 每次請求前調用*/PHP_RINIT_FUNCTION(test){ return SUCCESS;}/* /* 每次請求結束時調用*/PHP_RSHUTDOWN_FUNCTION(test){ return SUCCESS;}/* phpinfo()輸出擴充資訊*/PHP_MINFO_FUNCTION(test){ php_info_print_table_start(); php_info_print_table_header(2, "test support", "enabled"); php_info_print_table_end(); /* 是否輸出php.ini中的配置資訊 DISPLAY_INI_ENTRIES(); */}/* 定義函數my_function提供給PHP中使用 */PHP_FUNCTION(my_function){ char *arg = NULL; int arg_len, len; char *strg; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arg_len) == FAILURE) { return; } len = spprintf(&strg, 0, "Congratulations! You have successfully modified ext/%.78s/config.m4. Module %.78s is now compiled into PHP.", "test", arg); RETURN_STRINGL(strg, len, 0);}