成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Just for fun——PHP7擴(kuò)展編寫中的宏

qieangel2013 / 2797人閱讀

摘要:擴(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è)階段。

PHP擴(kuò)展

開發(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:

查看C文件
my_test.c
/* $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ù)返回值

可以設(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

相關(guān)文章

  • Just for fun——PHP GUI做一個(gè)貪吃蛇

    摘要:圖形用戶界面擴(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...

    kk_miles 評(píng)論0 收藏0
  • Just for fun——windows上bat管理你的Nginx+PHP+MySQL

    摘要:百度云盤下載地址文件目錄結(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); ...

    DangoSky 評(píng)論0 收藏0
  • Just for fun——windows上bat管理你的Nginx+PHP+MySQL

    摘要:百度云盤下載地址文件目錄結(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); ...

    wenshi11019 評(píng)論0 收藏0
  • Just for fun——windows上的php-fpm

    摘要:,配是通過一個(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...

    kel 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<