目標
建立一個名為 hello 的 PHP 擴充,並實現裡面唯一的函數 hello_world,作用是列印出 "Hello World" 字串。
前提條件
一台已經安裝了 C 編譯器、PHP 運行環境的電腦,一個稱手的文字編輯器。
重要提示:不要試圖在 Windows 下寫 PHP 擴充,Visual C、MinGW 的編譯器都不好用,我曾經搗鼓了一個多星期也沒能在 Windows 下編譯成功過。所以至少要在一個 Unix 環境下進行。Mac 和各種 Linux 環境都可以。
下載 PHP 原始碼
先用 php -v 確定系統上的 PHP 版本,再到 php.net 上下載相應的原始碼包。解壓到某個目錄下,如 php5-5.3.5。原始碼目錄裡,ext 目錄下即是所有的 PHP 擴充所在的地方,其他的目錄暫時不必考慮。
產生 PHP 擴充的架構代碼
在 php5-5.3.5/ext 目錄下,有一個名為 ext_skel 的檔案,這是用來建立擴充的一個簡便的工具。確保它有可執行許可權(chmod u+x ext_skel),在終端下執行
./ext_skel --extname=hello
即會在 ext 目錄下建立一個 hello 的目錄,裡面是初始的骨架代碼。下一步的任務是建立 hello 擴充,並實現 hello_world 函數。
編輯 config.m4
用文字編輯器開啟 ext/hello/config.m4,裡面有大量的注釋說明(以 dnl 開頭的行),基本上已經把很多問題說明白了。這裡要做的就是把
dnl PHP_ARG_ENABLE(hello, whether to enable hello support,dnl Make sure that the comment is aligned:dnl [ --enable-hello Enable hello support])
這三行取消注釋。這樣在接下來的編譯時間,可以用 ./configure --enable-hello 來編譯我們剛剛寫的擴充。
重建 configure
回到原始碼根目錄,運行 ./buildconf --force,會啟用 configure --enable-hello 參數。如果你在運行 buildconf 時報下面的錯誤:
buildconf: Your version of autoconf likely contains buggy cache code. Running vcsclean for you. To avoid this, install autoconf-2.13.
請安裝 autoconf-2.13(ubuntu 懶人的用法)
sudo apt-get install autoconf2.13
編譯擴充
此時的 hello 擴充已經可以編譯了,雖然還沒有實現其中的 hello_world 函數。先編譯一下,確保沒有環境配置上的問題。
./configure --enable-hellomake
經過一段時間(其實是把整個 PHP 也編譯出來了),用
./sapi/cli/php -f ext/hello/hello.php
檢查一下擴充編譯情況。不出意外的話,應該提示
Functions available in the test extension:confirm_hello_compiledCongratulations! You have successfully modified ext/hello/config.m4. Module hello is now compiled into PHP.
編寫 hello_world 函數
聲明函數:開啟 ext/hello/php_hello.h,在
PHP_MINIT_FUNCTION(hello);PHP_MSHUTDOWN_FUNCTION(hello);PHP_RINIT_FUNCTION(hello);PHP_RSHUTDOWN_FUNCTION(hello);PHP_MINFO_FUNCTION(hello);
後面添加
PHP_FUNCTION(hello_world);
即在擴充的標頭檔中聲明了 hello_world 的函數的原型。PHP_FUNCTION 是用來定義 PHP 函數的 C 語言宏。至於宏展開後的樣子,幾乎不用去想。只管用就可以了。
實現函數:開啟 hello.c,在檔案的末尾添加
PHP_FUNCTION(hello_world){php_printf("Hello World");return;}
這裡即是 hello_world 函數的實現。php_printf 的作用是向 SAPI 輸出一段字串,類似於 PHP 語言中的 echo。
接下來還需要將 hello_world 函數註冊到 zend_module_entry,這樣這個函數才能在 PHP 程式中變成“可見”的。找到
const zend_function_entry hello_functions[]={PHP_FE(confirm_hello_compiled,NULL)/* For testing, remove later. */{NULL, NULL, NULL}/* Must be the last line in hello_functions[] */};
將其修改為:
const zend_function_entry hello_functions[]={PHP_FE(confirm_hello_compiled,NULL)/* For testing, remove later. */PHP_FE(hello_world, NULL){NULL, NULL, NULL}/* Must be the last line in hello_functions[] */};
此時整個的 hello 擴充的代碼就編寫完了。最後再來 make 一下。
測試
在終端下運行 sapi/cli/php -r 'hello_world();echo "\n";',如果看到輸出“Hello World”,就成功了。
如何把擴充編譯成 .so 檔案
上面編譯的結果是把 hello 擴充編譯進了 PHP 核心中。如果想要編譯成 .so 擴充,以便發布出去的話。需要使用
./configure --enable-hello=sharedmake
這樣編譯完成後,會在 modules 目錄下產生 hello.so 檔案。把它複製到你的 PHP 運行環境的 extension_dir 下就可以像其他擴充一樣使用了。需要注意的是 PHP 版本。如果你是在 PHP 5.3.5 的原始碼環境中編譯的擴充,則產生的 .so 檔案只能用在 PHP 5.3.5 的運行環境中。
最後提一下,如果對 PHP 擴充有興趣,可以看看《Extending and Embedding PHP》這本書,作者還是個 MM。目前沒有中文版,英文電子版的自己搜。
摘自 lostwolf blog
http://www.bkjia.com/PHPjc/478541.htmlwww.bkjia.comtruehttp://www.bkjia.com/PHPjc/478541.htmlTechArticle目標 建立一個名為 hello 的 PHP 擴充,並實現裡面唯一的函數 hello_world,作用是列印出 Hello World 字串。 前提條件 一台已經安裝了 C 編譯器...