# 5.1 Your First Extension
### 配置文件
才開始,我們先用最快的(不是最標準的)的方式來建立一個代碼最少的擴展。在php源碼文件夾的ext目錄下創建一個新的文件夾,這里我取的名字叫做walu,它往往就是我們擴展的名字。其實這個文件夾可以放在任何一個位置,但是為了我們在后面介紹win32的編譯與靜態編譯,我們還是把它放在php源碼的ext目錄下。
現在,我們在這個目錄下創建一個config.m4文件,并輸入以下內容:
PHP_ARG_ENABLE(walu,
[Whether to enable the "walu" extension],
[ enable-walu Enable "walu" extension support])
if test $PHP_WALU != "no"; then
PHP_SUBST(WALU_SHARED_LIBADD)
PHP_NEW_EXTENSION(walu, walu.c, $ext_shared)
fi
上面PHP_ARG_ENABLE函數有三個參數,第一個參數是我們的擴展名(注意不用加引號),第二個參數是當我們運行./configure腳本時顯示的內容,最后一個參數則是我們在調用./configure --help時顯示的幫助信息。
> 也許有人會問,為什么有的擴展的開啟方式是 --enable-extname的形式,有的則是--with-extname的形式呢?其實兩者并沒有什么本質的不同,只不過enable多代表不依賴外部庫便可以直接編譯,而with大多需要依賴于第三方的lib。
> 現在,我們的擴展并不需要依賴其它的庫文件,所以我們直接使用--enable-walu便可以了。在第17章的時候我們將接觸通過CFLAGS和LDFLAGS來配置自己的擴展,使其依賴第三方庫文件才能被編譯成php擴展。
如果我們顯示運行./configure --enable-walu,那么終端環境便會自動將$PHP_WALU變量設置為yes,而PHP_SUBST函數只不過是php官方對autoconf里的AC_SUBST函數的一層封裝。
最后重要的一點是,PHP_NEW_EXTENSION函數聲明了這個擴展的名稱、需要的源文件名、此擴展的編譯形式。如果我們的擴展使用了多個文件,便可以將這多個文件名羅列在函數的參數里,如:
PHP_NEW_EXTENSION(sample, sample.c sample2.c sample3.c, $ext_shared)
最后的$ext_shared參數用來聲明這個擴展不是一個靜態模塊,而是在php運行時動態加載的。
下面,我們來編寫實現擴展主邏輯的源文件walu.c:
````c
//加載config.h,如果配置了的話
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
//加載php頭文件
#include "php.h"
#define phpext_walu_ptr &walu_module_entry
//module entry
zend_module_entry walu_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
STANDARD_MODULE_HEADER,
#endif
"walu", //這個地方是擴展名稱,往往我們會在這個地方使用一個宏。
NULL, /* Functions */
NULL, /* MINIT */
NULL, /* MSHUTDOWN */
NULL, /* RINIT */
NULL, /* RSHUTDOWN */
NULL, /* MINFO */
#if ZEND_MODULE_API_NO >= 20010901
"2.1", //這個地方是我們擴展的版本
#endif
STANDARD_MODULE_PROPERTIES
};
#ifdef COMPILE_DL_WALU
ZEND_GET_MODULE(walu)
#endif
````
這就是所有的代碼了,不過鑒于我們平時的開發習慣,往往會把這一份代碼分成兩份,一個.h文件,一個.c文件。上面的代碼只是生成了一基本的框架,而沒有任何實際的用處。
緊接著,創建一個zend_module_entry結構體,你肯定已經發現了,依據ZEND_MODULE_API_NO 是否大于等于 20010901,這個結構體需要不同的定義格式。20010901大約代表PHP4.2.0版本,所以我們現在的擴展幾乎都要包含STANDARD_MODULE_HEADER這個元素了。
其余六個成員我們可以先賦值為NULL,其實看看它們各自后面的注釋你就應該大體上了解它們各自是負責哪一方面的工作了。
最后,最底下的代碼用來標志我們的這個擴展是一個shared module。它是干么的呢?我也說不清楚,反正帶上就對了,否則擴展會工作不正常。原文解釋:This brief conditional simply adds a reference used by Zend when your extension is loaded dynamically. Don't worry about what it does or how it does it too much; just make sure that it's around or the next section won't work.
### 標準一些
根據我們平時的開發習慣,應該不會把所有代碼都寫在這一個文件里的,我們需要把上述代碼放在兩個文件里,一個頭文件,一個c文件。
````c
//php_walu.h
#ifndef WALU_H
#define WALU_H
//加載config.h,如果配置了的話
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
//加載php頭文件
#include "php.h"
#define phpext_walu_ptr &walu_module_entry
extern zend_module_entry walu_module_entry;
#endif
````
下面的是c文件
````c
//walu.c
#include "php_walu.h"
//module entry
zend_module_entry walu_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
STANDARD_MODULE_HEADER,
#endif
"walu", //這個地方是擴展名稱,往往我們會在這個地方使用一個宏。
NULL, /* Functions */
NULL, /* MINIT */
NULL, /* MSHUTDOWN */
NULL, /* RINIT */
NULL, /* RSHUTDOWN */
NULL, /* MINFO */
#if ZEND_MODULE_API_NO >= 20010901
"2.1", //這個地方是我們擴展的版本
#endif
STANDARD_MODULE_PROPERTIES
};
#ifdef COMPILE_DL_WALU
ZEND_GET_MODULE(walu)
#endif
````
## links
* 5 [Your First Extension](<5.md>)
* 5.2 [編譯我們的擴展](<5.2.md>)
- about
- 開始閱讀
- 目錄
- 1 PHP的生命周期
- 1.讓我們從SAPI開始
- 2.PHP的啟動與終止
- 3.PHP的生命周期
- 4.線程安全
- 5.小結
- 2 PHP變量在內核中的實現
- 1. 變量的類型
- 2. 變量的值
- 3. 創建PHP變量
- 4. 變量的存儲方式
- 5. 變量的檢索
- 6. 類型轉換
- 7. 小結
- 3 內存管理
- 1. 內存管理
- 2. 引用計數
- 3. 總結
- 4 動手編譯PHP
- 1. 編譯前的準備
- 2. PHP編譯前的config配置
- 3. Unix/Linux平臺下的編譯
- 4. 在Win32平臺上編譯PHP
- 5. 小結
- 5 Your First Extension
- 1. 一個擴展的基本結構
- 2. 編譯我們的擴展
- 3. 靜態編譯
- 4. 編寫函數
- 5. 小結
- 6 函數返回值
- 1. 一個特殊的參數:return_value
- 2. 引用與函數的執行結果
- 3. 小結
- 7 函數的參數
- 1. zend_parse_parameters
- 2. Arg Info 與類型綁定
- 3. 小結
- 8 使用HashTable與{數組}
- 1. 數組(C中的)與鏈表
- 2. 操作HashTable的API
- 3. 在內核中操作PHP語言中數組
- 4. 小結
- 9 PHP中的資源類型
- 1. 復合類型的數據——{資源}
- 2. Persistent Resources
- 3. {資源}自有的引用計數
- 4. 小結
- 10 PHP中的面向對象(一)
- 1. zend_class_entry
- 2. 定義一個類
- 3. 定義一個接口
- 4. 類的繼承與接口的實現
- 5. 小結
- 11 PHP中的面向對象(二)
- 1. 生成對象的實例與調用方法
- 2. 讀寫對象的屬性
- 3. 小結
- 12 啟動與終止的那點事
- 2. 小結
- 1. 關于生命周期
- 2. MINFO與phpinfo
- 3. 常量
- 4. PHP擴展中的全局變量
- 5. PHP語言中的超級全局變量
- 6. 小結
- 13 INI設置
- 1. 聲明和訪問ini設置
- 2. 小結
- 2. 小結
- 14 流式訪問
- 1. 概覽
- 2. 打開流
- 3. 訪問流
- 4. 靜態資源操作
- 5. 小結
- 15 流的實現
- 1. php流的表象之下
- 2. 包裝器操作
- 3. 實現一個包裝器
- 4. 操縱
- 5. 檢查
- 6. 小結
- 16 有趣的流
- 1. 上下文
- 2. 過濾器
- 3. 小結
- 17 配置和鏈接
- 1. autoconf
- 2. 庫的查找
- 3. 強制模塊依賴
- 4. Windows方言
- 5. 小結
- 18 擴展生成
- 1. ext_skel
- 2. PECL_Gen
- 3. 小結
- 19 設置宿主環境
- 1. 嵌入式SAPI
- 2. 構建并編譯一個宿主應用
- 3. 通過嵌入包裝重新創建cli
- 4. 老技術新用
- 5. 小結
- 20 高級嵌入式
- 1. 回調到php中
- 2. 錯誤處理
- 3. 初始化php
- 4. 覆寫INI_SYSTEM和INI_PERDIR選項
- 5. 捕獲輸出
- 6. 同時擴展和嵌入
- 7. 小結
- 約定