你的第一個擴展
每一個php擴展的構建至少需要兩個文件: 一個configuration文件, 它告訴編譯期要構建哪些文件以及需要什麼外部的庫, 還需要至少一個源文件, 它執行實際的工作.
剖析擴展
實際上, 通常會有第二個或第三個配置文件, 以及一個或多個頭文件. 對於你的第一個擴展, 你需要添加每種類型的一個文件並使用它們工作.
配置文件
要開始了, 首先在你的php源代碼目錄樹的ext/目錄下創建名為sample的目錄. 實際上這個新的目錄可以放在任何地方, 但是為了在本章後面演示win32和靜態構建選項, 我們還是先建立在源代碼目錄下吧.
下一步, 進入這個目錄, 創建一個名為config.m4的文件, 鍵入下面內容:
PHP_ARG_ENABLE(sample, [Whether to enable the "sample" extension], [ enable-sample Enable "sample" extension support]) if test $PHP_SAMPLE != "no"; then PHP_SUBST(SAMPLE_SHARED_LIBADD) PHP_NEW_EXTENSION(sample, sample.c, $ext_shared) fi
這是./configure時能夠調用enable-sample選項的最低要求.PHP_ARG_ENABLE的第二個參數將在./configure處理過程中到達這個擴展的配置文件時顯示. 第三個參數將在終端用戶執行./configure --help時顯示為幫助信息.
有沒有想過為什麼有的擴展配置使用enable-extname, 而有的擴展則使用with-extname? 功能上兩者沒有區別. 實際上, enable表示啟用這個特性不需要其他任何第三方庫, 相比之下, with則表示要使用這個特性還有其他先決條件
現在, 你的sample擴展並不需要和其他庫鏈接, 因此只需要使用enable版本. 在第17章"外部庫"中, 我們將介紹使用with並指示編譯器使用額外的CFLAGS和LDFLAGS設置.
如果終端用戶使用enable-sample選項調用了./configure, 那麼本地的環境變量$PHP_SAMPLE, 將被設置為yes. PHP_SUBST()是標准autoconf的AC_SUBST()宏的php修改版, 它在將擴展構建為共享模塊時需要.
最後但並不是不重要的, PHP_NEW_EXTENSION()定義了模塊並枚舉了所有必須作為擴展的一部分編譯的源文件. 如果需要多個文件, 它可以在第二個參數中使用空格分隔列舉, 例如:
PHP_NEW_EXTENSION(sample, sample.c sample2.c sample3.c, $ext_shared)
最後一個參數是對應於PHP_SUBST(SAMPLE_SHARED_LIBADD)命令的, 在構建共享模塊的時候同樣需要它.
頭文件
當使用C開發的時候, 將數據的類型定義放到外部的頭文件中隔離起來, 由源文件包含是常見的做法. 盡管php並不要求這樣, 但是這樣做在模塊增長到不能放到單個源文件時是有簡化作用的.
在你的php_sample.h頭文件中, 以下面內容開始:
#ifndef PHP_SAMPLE_H /* 防止重復包含 */ #define PHP_SAMPLE_H /* 定義擴展的屬性 */ #define PHP_SAMPLE_EXTNAME "sample" #define PHP_SAMPLE_EXTVER "1.0" /* 在php源碼樹外面構建時引入配置選項 */ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* 包含php的標准頭文件 */ #include "php.h" /* 定義入口點符號, Zend在加載這個模塊的時候使用 */ extern zend_module_entry sample_module_entry; #define phpext_sample_ptr &sample_module_entry #endif /* PHP_SAMPLE_H */
這個頭文件完成了兩個主要的任務: 如果擴展使用phpize工具構建(本書通常都使用這種方式), 那麼HAVE_CONFG_H就是已定義的, 這樣config.h就會被正常的包含進來. 無論擴展怎樣編譯, 都會從php源碼樹中包含php.h. 這個頭文件中包含了php源碼中訪問大部分PHPAPI要使用的其他頭文件.
接下來, 你的擴展使用的zend_module_entry結構定義為外部的, 這樣當這個模塊使用extension=xxx加載時, 就可以被Zend使用dlopen和dlsym()取到.
譯注: 關於模塊的加載過程, 請參考譯者的一篇博客<從dl('xxx.so');函數分析PHP模塊開發>(http://blog.csdn.net/lgg201/article/details/6584095)
頭文件中還會包含一些預處理, 定義將在原文件中使用的信息.
源代碼
最後, 最重要的你需要在sample.c中創建一個簡單的源碼骨架:
#include "php_sample.h" zend_module_entry sample_module_entry = { #if ZEND_MODULE_API_NO >= 20010901 STANDARD_MODULE_HEADER, #endif PHP_SAMPLE_EXTNAME, NULL, /* Functions */ NULL, /* MINIT */ NULL, /* MSHUTDOWN */ NULL, /* RINIT */ NULL, /* RSHUTDOWN */ NULL, /* MINFO */ #if ZEND_MODULE_API_NO >= 20010901 PHP_SAMPLE_EXTVER, #endif STANDARD_MODULE_PROPERTIES }; #ifdef COMPILE_DL_SAMPLE ZEND_GET_MODULE(sample) #endif