程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> PHP綜合 >> 編寫第一個php擴展

編寫第一個php擴展

編輯:PHP綜合

你的第一個擴展

每一個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

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved