首頁  >  文章  >  後端開發  >  如何寫一個php擴展

如何寫一個php擴展

伊谢尔伦
伊谢尔伦原創
2017-06-27 09:16:472711瀏覽

每一個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()取到.

頭檔中還會包含一些預處理, 定義將在原始檔中使用的資訊.

原始碼

#最後, 最重要的你需要在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

以上是如何寫一個php擴展的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn