淺析PHP Extension開(kāi)發(fā)基礎(chǔ)篇
PHP是當(dāng)前應(yīng)用非常廣泛的一門(mén)語(yǔ)言,從國(guó)外的Facebook、Twitter到國(guó)內(nèi)的淘寶、騰訊、百度再到互聯(lián)網(wǎng)上林林總總的各種大中小型網(wǎng)站都能見(jiàn)到它的身影。PHP的成功,應(yīng)該說(shuō)很大程度上依賴于其開(kāi)放的擴(kuò)展API機(jī)制和豐富的擴(kuò)展組件(PHP Extension),正是這些擴(kuò)展組件使得PHP從各種數(shù)據(jù)庫(kù)操作到XML、JSON、加密、文件處理、圖形處理、Socket等領(lǐng)域無(wú)所不能。有時(shí)候開(kāi)發(fā)人員可能需要開(kāi)發(fā)自己的PHP擴(kuò)展,當(dāng)前PHP5的擴(kuò)展機(jī)制是基于Zend API的,Zend API提供了豐富的接口和宏定義,加上一些實(shí)用工具,使得PHP擴(kuò)展開(kāi)發(fā)起來(lái)難度并不算特別大。本文將介紹關(guān)于PHP擴(kuò)展組件開(kāi)發(fā)的基本知識(shí),并通過(guò)一個(gè)實(shí)例展示開(kāi)發(fā)PHP擴(kuò)展的基本過(guò)程。
PHP擴(kuò)展組件的開(kāi)發(fā)過(guò)程在Unix和Windows環(huán)境下有所不同,但基本是互通的,本文將基于Unix環(huán)境(具體使用Linux)。閱讀本文需要簡(jiǎn)單了解Unix環(huán)境、PHP和C語(yǔ)言的一些基礎(chǔ)知識(shí),只要簡(jiǎn)單了解就行,我會(huì)盡量不涉及太過(guò)具體的操作系統(tǒng)和語(yǔ)言特性,并在必要的地方加以解釋,以便讀者閱讀。
本文的具體開(kāi)發(fā)環(huán)境為Ubuntu 10.04 + PHP 5.3.3。
下載PHP源代碼
要開(kāi)發(fā)PHP擴(kuò)展,第一步要下載PHP源代碼,因?yàn)槔锩嬗虚_(kāi)發(fā)擴(kuò)展需要的工具。我下載的是PHP最新版本5.3.3,格式為tar.bz2壓縮包。下載地址為:http://cn.php.net/get/php-5.3.3.tar.bz2/from/a/mirror。
下載后,將源代碼移動(dòng)到合適的目錄并解壓。解壓命令為:
- tar -jxvf 源碼包名稱
若下載的是tar.gz壓縮包,解壓命令為
- tar -zxvf 源碼包名稱
解壓后,在源代碼目錄中有個(gè)ext目錄,這里便是和PHP擴(kuò)展有關(guān)的目錄。進(jìn)入目錄后用ls查看,可以看到許多已經(jīng)存在的擴(kuò)展。下圖是在我的環(huán)境下查看的結(jié)果:
其中藍(lán)色的均是擴(kuò)展包目錄,其中可以看到我們很熟悉的mysql、iconv和gd等等。而ext_skel是Unix環(huán)境下用于自動(dòng)生成PHP擴(kuò)展框架的腳本工具,后面我們馬上會(huì)用到,ext_skel_win32.php是windows下對(duì)應(yīng)的腳本。
開(kāi)發(fā)自己的PHP擴(kuò)展——say_hello
下面我們開(kāi)發(fā)一個(gè)PHP擴(kuò)展:say_hello。這個(gè)擴(kuò)展很簡(jiǎn)單,只是接受一個(gè)字符串參數(shù),然后輸出“Hello xxx!”。這個(gè)例子只是為了介紹PHP擴(kuò)展組件的開(kāi)發(fā)流程,不承擔(dān)實(shí)際功能。
生成擴(kuò)展組件框架
PHP的擴(kuò)展組件開(kāi)發(fā)目錄和文件是有固定組織結(jié)構(gòu)的,你可以隨便進(jìn)入一個(gè)已有擴(kuò)展組件目錄,查看其所有文件,我想你一定眼花繚亂了。當(dāng)然你可以選擇手工完成框架的搭建,不過(guò)我相信你更希望有什么東西來(lái)幫你完成。上文提到的ext_skel腳本就是用來(lái)自動(dòng)構(gòu)建擴(kuò)展包框架的工具。ext_skel的完整命令為:
- ext_skel --extname=module [--proto=file] [--stubs=file] [--xml[=file]] [--skel=dir] [--full-xml] [--no-help]
作為初學(xué)者,我們不必了解所有命令參數(shù),實(shí)際上,大多數(shù)情況下只需要提供第一個(gè)參數(shù)就可以了,也就是擴(kuò)展模塊的名字。因此,我們?cè)趀xt目錄中鍵入如下命令:
- /ext_skel --extname=say_hello
(如果你希望詳細(xì)了解ext_skel的各項(xiàng)命令參數(shù),請(qǐng)參考這里)
這時(shí)再用ls查看,會(huì)發(fā)現(xiàn)多了一個(gè)“say_hello”目錄,進(jìn)入這個(gè)目錄,會(huì)發(fā)現(xiàn)ext_skel已經(jīng)為我們建立好了say_hello的基本框架,如下圖:
如果你懶得弄清楚PHP擴(kuò)展包目錄結(jié)構(gòu)的全部?jī)?nèi)容,那么里面有三個(gè)文件你必須注意:
config.m4:這是Unix環(huán)境下的Build System配置文件,后面將會(huì)通過(guò)它生成配置和安裝。
php_say_hello.h:這個(gè)文件是擴(kuò)展模塊的頭文件。遵循C語(yǔ)言一貫的作風(fēng),這個(gè)里面可以放置一些自定義的結(jié)構(gòu)體、全局變量等等。
say_hello.c:這個(gè)就是擴(kuò)展模塊的主程序文件了,最終的擴(kuò)展模塊各個(gè)函數(shù)入口都在這里。當(dāng)然,你可以將所有程序代碼都塞到這里面,也可以遵循模塊化思想,將各個(gè)功能模塊放到不同文件中。
下面的內(nèi)容主要圍繞這三個(gè)文件展開(kāi)。
Unix Build System配置
開(kāi)發(fā)PHP擴(kuò)展組件的第一步不是寫(xiě)實(shí)現(xiàn)代碼,而是要先配置好Build System選項(xiàng)。由于我們是在Linux下開(kāi)發(fā),所以這里的配置主要與config.m4有關(guān)。
關(guān)于Build System配置這一塊,要是寫(xiě)起來(lái)能寫(xiě)一大堆,而且與Unix系統(tǒng)很多東西相關(guān),就算我有興趣寫(xiě)估計(jì)大家也沒(méi)興趣看,所以這里我們從略,只揀關(guān)鍵地方說(shuō)一下,關(guān)于config.m4更多細(xì)節(jié)可以參考這里。
打開(kāi)生成的config.m4文件,內(nèi)容大致如下:
- dnl $Id$
- dnl config.m4 for extension say_hello
- dnl Comments in this file start with the string 'dnl'.
- dnl Remove where necessary. This file will not work
- dnl without editing.
- dnl If your extension references something external, use with:
- dnl PHP_ARG_WITH(say_hello, for say_hello support,
- dnl Make sure that the comment is aligned:
- dnl [ --with-say_hello Include say_hello support])
- dnl Otherwise use enable:
- dnl PHP_ARG_ENABLE(say_hello, whether to enable say_hello support,
- dnl Make sure that the comment is aligned:
- dnl [ --enable-say_hello Enable say_hello support])
- if test "$PHP_SAY_HELLO" != "no"; then
- dnl Write more examples of tests here...
- dnl # --with-say_hello -> check with-path
- dnl SEARCH_PATH="/usr/local /usr" # you might want to change this
- dnl SEARCH_FOR="/include/say_hello.h" # you most likely want to change this
- dnl if test -r $PHP_SAY_HELLO/$SEARCH_FOR; then # path given as parameter
- dnl SAY_HELLO_DIR=$PHP_SAY_HELLO
- dnl else # search default path list
- dnl AC_MSG_CHECKING([for say_hello files in default path])
- dnl for i in $SEARCH_PATH ; do
- dnl if test -r $i/$SEARCH_FOR; then
- dnl SAY_HELLO_DIR=$i
- dnl AC_MSG_RESULT(found in $i)
- dnl fi
- dnl done
- dnl fi
- dnl
- dnl if test -z "$SAY_HELLO_DIR"; then
- dnl AC_MSG_RESULT([not found])
- dnl AC_MSG_ERROR([Please reinstall the say_hello distribution])
- dnl fi
- dnl # --with-say_hello -> add include path
- dnl PHP_ADD_INCLUDE($SAY_HELLO_DIR/include)
- dnl # --with-say_hello -> check for lib and symbol presence
- dnl LIBNAME=say_hello # you may want to change this
- dnl LIBSYMBOL=say_hello # you most likely want to change this
- dnl PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL,
- dnl [
- dnl PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $SAY_HELLO_DIR/lib, SAY_HELLO_SHARED_LIBADD)
- dnl AC_DEFINE(HAVE_SAY_HELLOLIB,1,[ ])
- dnl ],[
- dnl AC_MSG_ERROR([wrong say_hello lib version or lib not found])
- dnl ],[
- dnl -L$SAY_HELLO_DIR/lib -lm
- dnl ])
- dnl
- dnl PHP_SUBST(SAY_HELLO_SHARED_LIBADD)
- PHP_NEW_EXTENSION(say_hello, say_hello.c, $ext_shared)
- fi
不要看這么多,因?yàn)樗幸?ldquo;dnl”開(kāi)頭的全是注釋,所以真正起作用沒(méi)幾行。這里需要配置的只有下面幾行:
- dnl If your extension references something external, use with:
- dnl PHP_ARG_WITH(say_hello, for say_hello support,
- dnl Make sure that the comment is aligned:
- dnl [ --with-say_hello Include say_hello support])
- dnl Otherwise use enable:
- dnl PHP_ARG_ENABLE(say_hello, whether to enable say_hello support,
- dnl Make sure that the comment is aligned:
- dnl [ --enable-say_hello Enable say_hello support])
我想大家也都能看明白,意思就是“如果你的擴(kuò)展引用了外部組件,使用…,否則使用…”。我們的say_hello擴(kuò)展并沒(méi)有引用外部組件,所以將“Otherwise use enable”下面三行的“dnl”去掉,改為:
- dnl Otherwise use enable:
- PHP_ARG_ENABLE(say_hello, whether to enable say_hello support,
- Make sure that the comment is aligned:
- [ --enable-say_hello Enable say_hello support])
保存,這樣關(guān)于Build System配置就大功告成了。
PHP Extension及Zend_Module結(jié)構(gòu)分析
以上可以看成是為開(kāi)發(fā)PHP擴(kuò)展而做的準(zhǔn)備工作,下面就要編寫(xiě)核心代碼了。上文說(shuō)過(guò),編寫(xiě)PHP擴(kuò)展是基于Zend API和一些宏的,所以如果要編寫(xiě)核心代碼,我們首先要弄清楚PHP Extension的結(jié)構(gòu)。因?yàn)橐粋€(gè)PHP Extension在C語(yǔ)言層面實(shí)際上就是一個(gè)zend_module_entry結(jié)構(gòu)體,這點(diǎn)可以從“php_say_hello.h”中得到證實(shí)。打開(kāi)“php_say_hello.h”,會(huì)看到里面有怎么一行:
- extern zend_module_entry say_hello_module_entry;
say_hello_module_entry就是say_hello擴(kuò)展的C語(yǔ)言對(duì)應(yīng)元素,而關(guān)于其類型zend_module_entry的定義可以在PHP源代碼的“Zend/zend_modules.h”文件里找到,下面代碼是zend_module_entry的定義:
- typedef struct _zend_module_entry zend_module_entry;
- struct _zend_module_entry {
- unsigned short size;
- unsigned int zend_api;
- unsigned char zend_debug;
- unsigned char zts;
- const struct _zend_ini_entry *ini_entry;
- const struct _zend_module_dep *deps;
- const char *name;
- const struct _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);
- const char *version;
- size_t globals_size;
- #ifdef ZTS
- ts_rsrc_id* globals_id_ptr;
- #else
- void* globals_ptr;
- #endif
- void (*globals_ctor)(void *global TSRMLS_DC);
- void (*globals_dtor)(void *global TSRMLS_DC);
- int (*post_deactivate_func)(void);
- int module_started;
- unsigned char type;
- void *handle;
- int module_number;
- char *build_id;
- };
這個(gè)結(jié)構(gòu)體可能看起來(lái)會(huì)讓人有點(diǎn)頭疼,不過(guò)我還是要解釋一下里面的內(nèi)容。因?yàn)檫@就是PHP Extension的原型,如果不搞清楚,就沒(méi)法開(kāi)發(fā)PHP Extension了。當(dāng)然,我就不一一對(duì)每個(gè)字段進(jìn)行解釋了,只揀關(guān)鍵的、這篇文章會(huì)用到的字段說(shuō),因?yàn)樵S多字段并不需要我們手工填寫(xiě),而是可以使用某些預(yù)定義的宏填充。
第7個(gè)字段“name”,這個(gè)字段是此PHP Extension的名字,在本例中就是“say_hello”。
第8個(gè)字段“functions”,這個(gè)將存放我們?cè)诖藬U(kuò)展中定義的函數(shù)的引用,具體結(jié)構(gòu)不再分析,有興趣的朋友可以閱讀_zend_function_entry的源代碼。具體編寫(xiě)代碼時(shí)這里會(huì)有相應(yīng)的宏。
第9-12個(gè)字段分別是四個(gè)函數(shù)指針,這四個(gè)函數(shù)會(huì)在相應(yīng)時(shí)機(jī)被調(diào)用,分別是“擴(kuò)展模塊加載時(shí)”、“擴(kuò)展模塊卸載時(shí)”、“每個(gè)請(qǐng)求開(kāi)始時(shí)”和“每個(gè)請(qǐng)求結(jié)束時(shí)”。這四個(gè)函數(shù)可以看成是一種攔截機(jī)制,主要用于相應(yīng)時(shí)機(jī)的資源分配、釋放等相關(guān)操作。
第13個(gè)字段“info_func”也是一個(gè)函數(shù)指針,這個(gè)指針指向的函數(shù)會(huì)在執(zhí)行phpinfo()時(shí)被調(diào)用,用于顯示自定義模塊信息。
第14個(gè)字段“version”是模塊的版本。
(關(guān)于zend_module_entry更詳盡的介紹請(qǐng)參考這里)
介紹完以上字段,我們可以看看“say_hello.c”中自動(dòng)生成的“say_hello_module_entry”框架代碼了。
- /* {{{ say_hello_module_entry
- */
- zend_module_entry say_hello_module_entry = {
- #if ZEND_MODULE_API_NO >= 20010901
- STANDARD_MODULE_HEADER,
- #endif
- "say_hello",
- say_hello_functions,
- PHP_MINIT(say_hello),
- PHP_MSHUTDOWN(say_hello),
- PHP_RINIT(say_hello), /* Replace with NULL if there's nothing to do at request start */
- PHP_RSHUTDOWN(say_hello), /* Replace with NULL if there's nothing to do at request end */
- PHP_MINFO(say_hello),
- #if ZEND_MODULE_API_NO >= 20010901
- "0.1", /* Replace with version number for your extension */
- #endif
- STANDARD_MODULE_PROPERTIES
- };
- /* }}} */
首先,宏“STANDARD_MODULE_HEADER”會(huì)生成前6個(gè)字段,“STANDARD_MODULE_PROPERTIES ”會(huì)生成“version”后的字段,所以現(xiàn)在我們還不用操心。而我們關(guān)心的幾個(gè)字段,也都填寫(xiě)好或由宏生成好了,并且在“say_hello.c”的相應(yīng)位置也生成了幾個(gè)函數(shù)的框架。這里要注意,幾個(gè)宏的參數(shù)均為“say_hello”,但這并不表示幾個(gè)函數(shù)的名字全為“say_hello”,C語(yǔ)言中也不可能存在函數(shù)名重載機(jī)制。實(shí)際上,在開(kāi)發(fā)PHP Extension的過(guò)程中,幾乎處處都要用到Zend里預(yù)定義的各種宏,從全局變量到函數(shù)的定義甚至返回值,都不能按照“裸寫(xiě)”的方式來(lái)編寫(xiě)C語(yǔ)言,這是因?yàn)镻HP的運(yùn)行機(jī)制可能會(huì)導(dǎo)致命名沖突等問(wèn)題,而這些宏會(huì)將函數(shù)等元素變換成一個(gè)內(nèi)部名稱,但這些對(duì)程序員都是透明的(除非你去閱讀那些宏的代碼),我們通過(guò)各種宏進(jìn)行編程,而宏則為我們處理很多內(nèi)部的東西。
寫(xiě)到這里,我們的任務(wù)就明了了:第一,如果需要在相應(yīng)時(shí)機(jī)處理一些東西,那么需要填充各個(gè)攔截函數(shù)內(nèi)容;第二,編寫(xiě)say_hello的功能函數(shù),并將引用添加到say_hello_functions中。
編寫(xiě)phpinfo()回調(diào)函數(shù)
因?yàn)閟ay_hello擴(kuò)展在各個(gè)生命周期階段并不需要做操作,所以我們只編寫(xiě)info_func的內(nèi)容,上文說(shuō)過(guò),這個(gè)函數(shù)將在phpinfo()執(zhí)行時(shí)被自動(dòng)調(diào)用,用于顯示擴(kuò)展的信息。編寫(xiě)這個(gè)函數(shù)會(huì)用到四個(gè)函數(shù):
php_info_print_table_start()——開(kāi)始phpinfo表格。無(wú)參數(shù)。
php_info_print_table_header()——輸出表格頭。第一個(gè)參數(shù)是整形,指明頭的列數(shù),然后后面的參數(shù)是與列數(shù)等量的(char*)類型參數(shù)用于指定顯示的文字。
php_info_print_table_row()——輸出表格內(nèi)容。第一個(gè)參數(shù)是整形,指明這一行的列數(shù),然后后面的參數(shù)是與列數(shù)等量的(char*)類型參數(shù)用于指定顯示的文字。
php_info_print_table_end()——結(jié)束phpinfo表格。無(wú)參數(shù)。
下面是“say_hello.c”中需要編寫(xiě)的info_func的具體代碼:
- /* {{{ PHP_MINFO_FUNCTION
- */
- PHP_MINFO_FUNCTION(say_hello)
- {
- php_info_print_table_start();
- php_info_print_table_header(2, "say_hello support", "enabled");
- php_info_print_table_row(2, "author", "Zhang Yang"); /* Replace with your name */
- php_info_print_table_end();
- /* Remove comments if you have entries in php.ini
- DISPLAY_INI_ENTRIES();
- */
- }
- /* }}} */
編寫(xiě)核心函數(shù)
編寫(xiě)核心函數(shù),總共分為三步:1、使用宏P(guān)HP_FUNCTION定義函數(shù)體;2、使用宏ZEND_BEGIN_ARG_INFO和ZEND_END_ARG_INFO定義參數(shù)信息;3、使用宏P(guān)HP_FE將函數(shù)加入到say_hello_functions中。下面分步說(shuō)明。
使用宏P(guān)HP_FUNCTION定義函數(shù)體
- PHP_FUNCTION(say_hello_func)
- {
- char *name;
- int name_len;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE)
- {
- return;
- }
- php_printf("Hello %s!", name);
- RETURN_TRUE;
- }
上文說(shuō)過(guò),編寫(xiě)PHP擴(kuò)展時(shí)幾乎所有東西都不能裸寫(xiě),而是必須使用相應(yīng)的宏。從上面代碼可以清楚看到這一點(diǎn)。總體來(lái)說(shuō),核心函數(shù)代碼一般由如下幾部分構(gòu)成:
定義函數(shù),這一步通過(guò)宏P(guān)HP_FUNCTION實(shí)現(xiàn),函數(shù)的外部名稱就是宏后面括號(hào)里面的名稱。
聲明并定義局部變量。
解析參數(shù),這一步通過(guò)zend_parse_parameters函數(shù)實(shí)現(xiàn),這個(gè)函數(shù)的作用是從函數(shù)用戶的輸入棧中讀取數(shù)據(jù),然后轉(zhuǎn)換成相應(yīng)的函數(shù)參數(shù)填入變量以供后面核心功能代碼使用。zend_parse_parameters的第一個(gè)參數(shù)是用戶傳入?yún)?shù)的個(gè)數(shù),可以由宏“ZEND_NUM_ARGS() TSRMLS_CC”生成;第二個(gè)參數(shù)是一個(gè)字符串,其中每個(gè)字母代表一個(gè)變量類型,我們只有一個(gè)字符串型變量,所以第二個(gè)參數(shù)是“s”;最后各個(gè)參數(shù)需要一些必要的局部變量指針用于存儲(chǔ)數(shù)據(jù),下表給出了不同變量類型的字母代表及其所需要的局部變量指針。
參數(shù)解析完成后就是核心功能代碼,我們這里只是輸出一行字符,php_printf是Zend版本的printf。
最后的返回值也是通過(guò)宏實(shí)現(xiàn)的。RETURN_TRUE宏是返回布爾值“true”。
使用宏ZEND_BEGIN_ARG_INFO和ZEND_END_ARG_INFO定義參數(shù)信息
參數(shù)信息是函數(shù)所必要部分,這里不做深究,直接給出相應(yīng)代碼:
- ZEND_BEGIN_ARG_INFO(arginfo_say_hello_func, 0)
- ZEND_END_ARG_INFO()
如需了解具體信息請(qǐng)閱讀相關(guān)宏定義。
使用宏P(guān)HP_FE將函數(shù)加入到say_hello_functions中
最后,我們需要將剛才定義的函數(shù)和參數(shù)信息加入到say_hello_functions數(shù)組里,代碼如下:
- const zend_function_entry say_hello_functions[] = {
- PHP_FE(say_hello_func, arginfo_say_hello_func)
- {NULL, NULL, NULL}
- };
這一步就是通過(guò)PHP_EF宏實(shí)現(xiàn),注意這個(gè)數(shù)組最后一行必須是{NULL, NULL, NULL} ,請(qǐng)不要?jiǎng)h除。
下面是編寫(xiě)完成后的say_hello.c全部代碼:
- /*
- +---------------------------------------------------------------------+
- | PHP Version 5 |
- +----------------------------------------------------------------------+
- | Copyright (c) 1997-2010 The PHP Group |
- +----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
- +----------------------------------------------------------------------+
- | Author: |
- +----------------------------------------------------------------------+
- */
- /* $Id: header 297205 2010-03-30 21:09:07Z johannes $ */
- #ifdef HAVE_CONFIG_H
- #include "config.h"
- #endif
- #include "php.h"
- #include "php_ini.h"
- #include "ext/standard/info.h"
- #include "php_say_hello.h"
- /* If you declare any globals in php_say_hello.h uncomment this:
- ZEND_DECLARE_MODULE_GLOBALS(say_hello)
- */
- /* True global resources - no need for thread safety here */
- static int le_say_hello;
- /* {{{ PHP_FUNCTION
- */
- PHP_FUNCTION(say_hello_func)
- {
- char *name;
- int name_len;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE)
- {
- return;
- }
- php_printf("Hello %s!", name);
- RETURN_TRUE;
- }
- ZEND_BEGIN_ARG_INFO(arginfo_say_hello_func, 0)
- ZEND_END_ARG_INFO()
- /* }}} */
- /* {{{ say_hello_functions[]
- *
- * Every user visible function must have an entry in say_hello_functions[].
- */
- const zend_function_entry say_hello_functions[] = {
- PHP_FE(say_hello_func, arginfo_say_hello_func)
- {NULL, NULL, NULL} /* Must be the last line in say_hello_functions[] */
- };
- /* }}} */
- /* {{{ say_hello_module_entry
- */
- zend_module_entry say_hello_module_entry = {
- #if ZEND_MODULE_API_NO >= 20010901
- STANDARD_MODULE_HEADER,
- #endif
- "say_hello",
- say_hello_functions,
- NULL,
- NULL,
- NULL,
- NULL,
- PHP_MINFO(say_hello),
- #if ZEND_MODULE_API_NO >= 20010901
- "0.1", /* Replace with version number for your extension */
- #endif
- STANDARD_MODULE_PROPERTIES
- };
- /* }}} */
- #ifdef COMPILE_DL_SAY_HELLO
- ZEND_GET_MODULE(say_hello)
- #endif
- /* {{{ PHP_MINFO_FUNCTION
- */
- PHP_MINFO_FUNCTION(say_hello)
- {
- php_info_print_table_start();
- php_info_print_table_header(2, "say_hello support", "enabled");
- php_info_print_table_row(2, "author", "Zhang Yang"); /* Replace with your name */
- php_info_print_table_end();
- /* Remove comments if you have entries in php.ini
- DISPLAY_INI_ENTRIES();
- */
- }
- /* }}} */
編譯并安裝擴(kuò)展
在say_hello目錄下輸入下面命令:
- /usr/bin/phpize
- ./configure
- make
- make install
這樣就完成了say_hello擴(kuò)展的安裝(如果沒(méi)有報(bào)錯(cuò)的話)。
這時(shí)如果你去放置php擴(kuò)展的目錄下,會(huì)發(fā)現(xiàn)多了一個(gè)say_hello.so的文件。如下圖所示:
下面就是將其加入到php.ini配置中,然后重啟Apache(如果需要的話)。這些都是PHP基本配置的內(nèi)容,我就不詳述了。
擴(kuò)展測(cè)試
如果上面順利完成,這時(shí)運(yùn)行phpinfo(),應(yīng)該能看到如下信息:
這說(shuō)明擴(kuò)展已經(jīng)安裝成功了。然后我們編寫(xiě)一個(gè)測(cè)試用PHP腳本:
- php
- say_hello_func('Zhang Yang');
- ?>
執(zhí)行這個(gè)腳本,結(jié)果如下:
說(shuō)明擴(kuò)展已經(jīng)正常工作了。
總結(jié)
這篇文章主要用示例方法介紹PHP Extension的開(kāi)發(fā)基礎(chǔ)。在PHP的使用中,也許是因?yàn)樾枰С中碌慕M件(如新的數(shù)據(jù)庫(kù)),又或是業(yè)務(wù)需要或性能需要,幾乎都會(huì)遇到需要開(kāi)發(fā)PHP擴(kuò)展的地方。后續(xù)如果有機(jī)會(huì),我會(huì)寫(xiě)文章介紹一些關(guān)于擴(kuò)展開(kāi)發(fā)較為深入的東西,如擴(kuò)展模塊生命周期、INI使用以及編寫(xiě)面向?qū)ο蟮臄U(kuò)展模塊等等。
原文鏈接:http://www.cnblogs.com/leoo2sk/archive/2010/12/09/talk-about-php-ext-develop-basic.html
【編輯推薦】
- 讓PHP開(kāi)發(fā)者事半功倍的十大技巧
- PHP開(kāi)發(fā)者不可不知的五件事
- 優(yōu)秀的PHP開(kāi)發(fā)者是怎樣煉成的?
- 十款PHP開(kāi)發(fā)者值得關(guān)注的編碼工具