摘要:擴(kuò)展開發(fā)者可以通過實(shí)現(xiàn)自定義的功能,通過擴(kuò)展嵌入到中。就是這個(gè)擴(kuò)展注冊(cè)的函數(shù)數(shù)組。
PHP內(nèi)核架構(gòu)
SAPI是PHP的最上層,它是PHP的應(yīng)用接口層,對(duì)于源碼目錄為sapi
main是PHP的主要代碼,主要是輸入/輸出,Web通信,以及PHP框架的初始化操作,對(duì)于源碼目錄為main
ZendVM是PHP解釋器的主要實(shí)現(xiàn),即ZendVM,對(duì)于源碼目錄為Zend
截一張php-src的圖,目錄都有對(duì)應(yīng)
PHP的生命周期
PHP根據(jù)不同SAPI的實(shí)現(xiàn),各階段的執(zhí)行情況有些差異。譬如cli模式的話,完整地經(jīng)歷了這些階段,而Fastcgi模式下則在啟動(dòng)時(shí)執(zhí)行一次模塊初始化,然后各個(gè)請(qǐng)求只經(jīng)歷請(qǐng)求初始化,執(zhí)行請(qǐng)求腳本,請(qǐng)求關(guān)閉這幾個(gè)階段。
開發(fā)者可以通過C/C++實(shí)現(xiàn)自定義的功能,通過擴(kuò)展嵌入到PHP中。
編寫擴(kuò)展的步驟:
通過ext目錄下ext_skel腳本生成擴(kuò)展的基本框架./ext_skel --extname=module (module is the name of your extension)
修改config.m4配置:設(shè)置編譯配置參數(shù)、設(shè)置擴(kuò)展源文件
編寫擴(kuò)展源代碼
生成configure:寫完后先phpize(在php的bin目錄下)運(yùn)行一下
編譯&安裝: ./configure、 make、make install,然后改一下php.ini文件,添加一下.so文件
舉例操作系統(tǒng):CentOS Linux release 7.3.1611
PHP版本:PHP 7.1.11
./ext_skel --extname=my_test --no-help
--no-help是略去注釋代碼(干凈點(diǎn))
生成目錄my_test:
/* $Salamander$ */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "php.h" #include "php_ini.h" #include "ext/standard/info.h" #include "php_my_test.h" static int le_my_test; PHP_MINIT_FUNCTION(my_test) { return SUCCESS; } PHP_MSHUTDOWN_FUNCTION(my_test) { return SUCCESS; } PHP_RINIT_FUNCTION(my_test) { #if defined(COMPILE_DL_MY_TEST) && defined(ZTS) ZEND_TSRMLS_CACHE_UPDATE(); #endif return SUCCESS; } PHP_RSHUTDOWN_FUNCTION(my_test) { return SUCCESS; } PHP_MINFO_FUNCTION(my_test) { php_info_print_table_start(); php_info_print_table_header(2, "my_test support", "enabled"); php_info_print_table_end(); } const zend_function_entry my_test_functions[] = { PHP_FE_END }; zend_module_entry my_test_module_entry = { STANDARD_MODULE_HEADER, "my_test", my_test_functions, PHP_MINIT(my_test), PHP_MSHUTDOWN(my_test), PHP_RINIT(my_test), PHP_RSHUTDOWN(my_test), PHP_MINFO(my_test), PHP_MY_TEST_VERSION, STANDARD_MODULE_PROPERTIES }; #ifdef COMPILE_DL_MY_TEST #ifdef ZTS ZEND_TSRMLS_CACHE_DEFINE() #endif ZEND_GET_MODULE(my_test) #endif
可以注意到這里有一些宏
PHP_MINIT_FUNCTION
PHP_MSHUTDOWN_FUNCTION
PHP_RINIT_FUNCTION
PHP_RSHUTDOWN_FUNCTION
PHP_MINFO_FUNCTION
這些是PHP提供的鉤子函數(shù),PHP執(zhí)行到不同的階段時(shí)回調(diào)各個(gè)擴(kuò)展定義的鉤子函數(shù),定義完成后,最后設(shè)置一下zend_module_entry對(duì)應(yīng)的函數(shù)指針即可。
回顧之前的PHP的生命周期,也就是說(=>指對(duì)應(yīng)某個(gè)階段):
PHP_MINIT_FUNCTION => 模塊初始化階段(M就是module的含義,init就是initial)
PHP_MSHUTDOWN_FUNCTION => 模塊關(guān)閉階段(M就是module的含義,后面就是shutdown)
PHP_RINIT_FUNCTION => 請(qǐng)求初始化(R就是request的含義,init就是initial)
PHP_RSHUTDOWN_FUNCTION => 請(qǐng)求關(guān)閉階段(R就是request的含義,后面就是shutdown)
PHP_MINFO_FUNCTION 指獲取模塊信息
最后,設(shè)置zend_module_entry這個(gè)結(jié)構(gòu)體
zend_module_entry my_test_module_entry = { STANDARD_MODULE_HEADER, "my_test", my_test_functions, PHP_MINIT(my_test), PHP_MSHUTDOWN(my_test), PHP_RINIT(my_test), PHP_RSHUTDOWN(my_test), PHP_MINFO(my_test), PHP_MY_TEST_VERSION, STANDARD_MODULE_PROPERTIES };
獲取各個(gè)鉤子函數(shù)的指針,有對(duì)對(duì)應(yīng)的宏P(guān)HP_MINIT,PHP_MSHUTDOWN,PHP_RINIT,PHP_RSHUTDOWN,PHP_MINFO
注冊(cè)函數(shù)分為兩步:
定義函數(shù),可以通過PHP_FUNCTION()或ZEND_FUNCTION()宏來完成函數(shù)聲明
注冊(cè)函數(shù),PHP提供了zend_function_entry,擴(kuò)展只需為每個(gè)內(nèi)部函數(shù)生成這樣一個(gè)結(jié)構(gòu),然后將所有函數(shù)的結(jié)構(gòu)數(shù)組提供給zend_module_entry->functions即可
For Example:
PHP_FUNCTION(my_func) { // 具體實(shí)現(xiàn) }
展開后
void zif_my_func(zend_execute_data *execute_data, zval *return_value) { // ... }
zend_function_entry可以通過宏P(guān)HP_FE或ZEND_FE生成(FE即function entry)。
const zend_function_entry my_test_functions[] = { PHP_FE(my_func, NULL) PHP_FE_END };
my_test_functions就是這個(gè)擴(kuò)展注冊(cè)的函數(shù)數(shù)組。
最后,它設(shè)置在了zend_module_entry(第三個(gè)參數(shù))
zend_module_entry my_test_module_entry = { STANDARD_MODULE_HEADER, "my_test", my_test_functions, PHP_MINIT(my_test), PHP_MSHUTDOWN(my_test), PHP_RINIT(my_test), PHP_RSHUTDOWN(my_test), PHP_MINFO(my_test), PHP_MY_TEST_VERSION, STANDARD_MODULE_PROPERTIES };函數(shù)參數(shù)解析
PHP提供了一個(gè)方法將zend_execute_data上的參數(shù)解析到指定變量上。
//file: Zend/zend_API.h ZEND_API int zend_parse_parameters(int num_args, const char *type_spec, ...)
num_args:參數(shù)數(shù)量,用ZEND_NUM_ARGS()可以獲取
type_spec 為參數(shù)解析規(guī)則,是一個(gè)字符串
最后一個(gè)是可變參數(shù),指定要解析到的變量地址
舉例:
PHP_FUNCTION(my_func) { zval *arr; if(zend_parse_parameters(ZEND_NUM_ARGS(), "a", &a) == FAILURE) { RETURN_FALSE; } ... }
如果有多個(gè)變量type_spec可以變?yōu)?la",l表示整型,a表示數(shù)組(另外還有b:布爾型,s:字符串型,o:對(duì)象)
,后面則改為&a, &b
可以設(shè)置return_value,但PHP提供了設(shè)置了設(shè)置返回值的宏
#define RETURN_BOOL(b) { RETVAL_BOOL(b); return; } #define RETURN_NULL() { RETVAL_NULL(); return;} #define RETURN_LONG(l) { RETVAL_LONG(l); return; } #define RETURN_DOUBLE(d) { RETVAL_DOUBLE(d); return; } #define RETURN_STR(s) { RETVAL_STR(s); return; } #define RETURN_INTERNED_STR(s) { RETVAL_INTERNED_STR(s); return; } #define RETURN_NEW_STR(s) { RETVAL_NEW_STR(s); return; } #define RETURN_STR_COPY(s) { RETVAL_STR_COPY(s); return; } #define RETURN_STRING(s) { RETVAL_STRING(s); return; } #define RETURN_STRINGL(s, l) { RETVAL_STRINGL(s, l); return; } #define RETURN_EMPTY_STRING() { RETVAL_EMPTY_STRING(); return; } #define RETURN_RES(r) { RETVAL_RES(r); return; } #define RETURN_ARR(r) { RETVAL_ARR(r); return; } #define RETURN_OBJ(r) { RETVAL_OBJ(r); return; } #define RETURN_ZVAL(zv, copy, dtor) { RETVAL_ZVAL(zv, copy, dtor); return; } #define RETURN_FALSE { RETVAL_FALSE; return; } #define RETURN_TRUE { RETVAL_TRUE; return; }寫個(gè)小例子
寫一個(gè)兩個(gè)整型變量相加的函數(shù)
/* $Salamander$ */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "php.h" #include "php_ini.h" #include "ext/standard/info.h" #include "php_my_test.h" static int le_my_test; PHP_FUNCTION(my_add) { int argc = ZEND_NUM_ARGS(); zend_long a; zend_long b; if (zend_parse_parameters(argc, "ll", &a, &b) == FAILURE) RETURN_FALSE; RETURN_LONG(a + b); } PHP_MINIT_FUNCTION(my_test) { return SUCCESS; } PHP_MSHUTDOWN_FUNCTION(my_test) { return SUCCESS; } PHP_RINIT_FUNCTION(my_test) { #if defined(COMPILE_DL_MY_TEST) && defined(ZTS) ZEND_TSRMLS_CACHE_UPDATE(); #endif return SUCCESS; } PHP_RSHUTDOWN_FUNCTION(my_test) { return SUCCESS; } PHP_MINFO_FUNCTION(my_test) { php_info_print_table_start(); php_info_print_table_header(2, "my_test support", "enabled"); php_info_print_table_end(); } const zend_function_entry my_test_functions[] = { PHP_FE(my_add, NULL) PHP_FE_END }; zend_module_entry my_test_module_entry = { STANDARD_MODULE_HEADER, "my_test", my_test_functions, PHP_MINIT(my_test), PHP_MSHUTDOWN(my_test), PHP_RINIT(my_test), PHP_RSHUTDOWN(my_test), PHP_MINFO(my_test), PHP_MY_TEST_VERSION, STANDARD_MODULE_PROPERTIES }; #ifdef COMPILE_DL_MY_TEST #ifdef ZTS ZEND_TSRMLS_CACHE_DEFINE() #endif ZEND_GET_MODULE(my_test) #endif
config.m4中取消以下注釋(刪除dnl即可)
dnl PHP_ARG_ENABLE(my_test, whether to enable my_test support, dnl Make sure that the comment is aligned: dnl [ --enable-my_test Enable my_test support])
然后在my_test目錄下執(zhí)行
phpize ./configure --with-php-config=/usr/local/php7.1/bin/php-config
php-config這個(gè)腳本是獲取PHP安裝信息的(PHP安裝路徑,PHP版本,PHP源碼的頭文件目錄,LDFLAGS,依賴的外部庫(kù),PHP編譯參數(shù)),它在php的安裝路徑的bin目錄下,如果你不指定--with-php-config的話,將到默認(rèn)的PHP的安裝路徑下搜索(安裝了多個(gè)PHP版本時(shí)最好指定一下,可能會(huì)編譯不通過)
然后
make && make install
得到
Installing shared extensions: /usr/local/php7.1/lib/php/extensions/no-debug-zts-20160303/
修改php.ini文件,加入.so
date.timezone = "Asia/Shanghai" display_errors = On error_reporting = E_ALL short_open_tag=Off upload_max_filesize = 50M post_max_size = 50M memory_limit=512M extension=my_test.so測(cè)試加載
php -m測(cè)試函數(shù)
php -r "echo my_add(1, 3);"
函數(shù)調(diào)用成功。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/28162.html
摘要:圖形用戶界面擴(kuò)展今天閱讀手冊(cè)的時(shí)候看到有這個(gè)圖形庫(kù)的擴(kuò)展,所以咱趕新鮮用一用安裝擴(kuò)展官方手冊(cè)的安裝步驟是的要求文檔寫著到上下載的,我用的是位,所以用了這個(gè)下載下來的文件目錄結(jié)構(gòu)接下來放入到的目錄中,然后加入和放入目錄中,也就 圖形用戶界面(GUI) 擴(kuò)展 今天閱讀PHP手冊(cè)的時(shí)候,看到PHP7有ui這個(gè)圖形庫(kù)的擴(kuò)展,所以咱趕新鮮用一用 安裝擴(kuò)展 官方手冊(cè)的安裝步驟是linux的: Re...
摘要:百度云盤下載地址文件目錄結(jié)構(gòu)為開啟的腳本為開啟的腳本為開啟服務(wù)的腳本為開啟上述所有進(jìn)程的腳本為關(guān)閉所有進(jìn)程的腳本如果你更喜歡程序,可以使用簡(jiǎn)單使用手冊(cè)把,,壓縮包解壓,并命名為,,標(biāo)識(shí)一下新版本而已,以下配置文件用修改即可目錄中把或者 百度云盤下載地址 文件目錄結(jié)構(gòu) showImg(https://segmentfault.com/img/bVVFMU?w=757&h=380); ...
摘要:百度云盤下載地址文件目錄結(jié)構(gòu)為開啟的腳本為開啟的腳本為開啟服務(wù)的腳本為開啟上述所有進(jìn)程的腳本為關(guān)閉所有進(jìn)程的腳本如果你更喜歡程序,可以使用簡(jiǎn)單使用手冊(cè)把,,壓縮包解壓,并命名為,,標(biāo)識(shí)一下新版本而已,以下配置文件用修改即可目錄中把或者 百度云盤下載地址 文件目錄結(jié)構(gòu) showImg(https://segmentfault.com/img/bVVFMU?w=757&h=380); ...
摘要:,配是通過一個(gè)類似的協(xié)議,升級(jí)版的的。在上有幫你管理進(jìn)程,在似乎沒有,這是有點(diǎn)令人悲傷的。檢驗(yàn)一下然后開啟然后配置中里文件在盤建立一個(gè)的文件夾,放入,開啟測(cè)試寫入訪問應(yīng)用我的項(xiàng)目就用了這個(gè)東西,,歡迎 fastcgi As we all know,nginx配php是通過fastcgi(一個(gè)類似http的協(xié)議,升級(jí)版的cgi)的。在linux上有php-fpm幫你管理進(jìn)程,在windo...
閱讀 3807·2021-08-11 11:16
閱讀 1647·2019-08-30 15:44
閱讀 2014·2019-08-29 18:45
閱讀 2301·2019-08-26 18:18
閱讀 1032·2019-08-26 13:37
閱讀 1590·2019-08-26 11:43
閱讀 2145·2019-08-26 11:34
閱讀 400·2019-08-26 10:59