PHP擴展代碼結構詳解

PHP擴展代碼結構詳解 

這個是繼:使用ext_skel和phpize構建php5擴展  內容 (拆分出來) Zend_API:深刻_PHP_內核:http://cn2.php.net/manual/zh/internals2.ze1.php
咱們使用ext_skel建立擴展 hello_module,該模塊包含一個方法:hello_world。
php

使用ext_skel 生成的代碼都是PHP_開頭的宏, 而不是ZEND_開頭. 實際上這二者是同樣的。mysql

在源代碼src/main/PHP.h 中發現: PHP_FUNCTION 就是ZEND_FUNCTION的別名,即:sql

  1. #define PHP_FUNCTION            ZEND_FUNCTION   /* <acronym title="Hypertext Preprocessor">PHP</acronym>-named Zend macro wrappers */   

其實,不少」PHP_」開頭的宏都用對應的」ZEND_」開頭的宏,這個應該是爲兼容以前的版本吧。vim

php_hello_module.hapi

  1. /* $Id: header 252479 2008-02-07 19:39:50Z iliaa $ */  
  2.   
  3. #ifndef PHP_HELLO_MODULE_H  
  4. #define PHP_HELLO_MODULE_H  
  5.   
  6. extern zend_module_entry hello_module_module_entry;  
  7. #define phpext_hello_module_ptr &hello_module_module_entry  
  8.   
  9. #ifdef PHP_WIN32  
  10. #   define PHP_HELLO_MODULE_API __declspec(dllexport)  
  11. #elif defined(__GNUC__) && __GNUC__ >= 4  
  12. #   define PHP_HELLO_MODULE_API __attribute__ ((visibility("default")))  
  13. #else  
  14. #   define PHP_HELLO_MODULE_API  
  15. #endif  
  16.   
  17. #ifdef ZTS  
  18. #include "TSRM.h"  
  19. #endif  
  20.   
  21. PHP_MINIT_FUNCTION(hello_module);    //聲明加載模塊時調用的函數  
  22. PHP_MSHUTDOWN_FUNCTION(hello_module);//聲明卸載模塊時調用的函數  
  23. PHP_RINIT_FUNCTION(hello_module);    //聲明請求時調用的函數  
  24. PHP_RSHUTDOWN_FUNCTION(hello_module);//聲明請求結束時調用的函數  
  25. PHP_MINFO_FUNCTION(hello_module);    //聲明模塊信息函數,便可以在phpinfo看到的信息  
  26.   
  27. PHP_FUNCTION(confirm_hello_module_compiled);    /* For testing, remove later. */  
  28. /*********** 2)聲明導出函數   ************************************************/  
  29. PHP_FUNCTION(hello_world);    
  30.   
  31. /*  
  32.     Declare any global variables you may need between the BEGIN 
  33.     and END macros here:      
  34.  
  35. ZEND_BEGIN_MODULE_GLOBALS(hello_module) 
  36.     long  global_value; 
  37.     char *global_string; 
  38. ZEND_END_MODULE_GLOBALS(hello_module) 
  39. */  
  40.   
  41. /* In every utility function you add that needs to use variables  
  42.    in php_hello_module_globals, call TSRMLS_FETCH(); after declaring other  
  43.    variables used by that function, or better yet, pass in TSRMLS_CC 
  44.    after the last function argument and declare your utility function 
  45.    with TSRMLS_DC after the last declared argument.  Always refer to 
  46.    the globals in your function as HELLO_MODULE_G(variable).  You are  
  47.    encouraged to rename these macros something shorter, see 
  48.    examples in any other php module directory. 
  49. */  
  50.   
  51. #ifdef ZTS  
  52. #define HELLO_MODULE_G(v) TSRMG(hello_module_globals_id, zend_hello_module_globals *, v)  
  53. #else  
  54. #define HELLO_MODULE_G(v) (hello_module_globals.v)  
  55. #endif  
  56.   
  57. #endif  /* PHP_HELLO_MODULE_H */  

hello_module.c數組


  1. /* $Id: header 252479 2008-02-07 19:39:50Z iliaa $ */  
  2.   
  3. #ifdef HAVE_CONFIG_H  
  4. #include "config.h"  
  5. #endif  
  6.   
  7. /***********************1)包含頭文件(引入所須要的宏、API定義等) **************************/  
  8. #include "php.h" //1)包含頭文件(引入所須要的宏、API定義等);#include "php_ini.h"#include "ext/standard/info.h"#include "php_hello_module.h"/* If you declare any globals in php_hello_module.h uncomment this:ZEND_DECLARE_MODULE_GLOBALS(hello_module)*//* True global resources - no need for thread safety here */static int le_hello_module;  
  9. /************ 3)聲明(引入)Zend(PHP)函數塊 ******************/  
  10. /* {{{ hello_module_functions[] * * Every user visible function must have an entry in hello_module_functions[]. */  
  11. const zend_function_entry hello_module_functions[] = {  
  12.         PHP_FE(hello_world, NULL)  
  13.     PHP_FE(confirm_hello_module_compiled,   NULL)       /* For testing, remove later. */  
  14.     {NULL, NULL, NULL}  /* Must be the last line in hello_module_functions[] */  
  15. };  
  16. /* }}} */  
  17.   
  18.   
  19. /*********************************4)聲明 Zend模塊  ***********************/  
  20.   
  21. /* {{{ hello_module_module_entry 
  22.  */  
  23. zend_module_entry hello_module_module_entry = {  
  24. #if ZEND_MODULE_API_NO >= 20010901  
  25.     STANDARD_MODULE_HEADER,  
  26. #endif  
  27.        "hello_module",  
  28.     hello_module_functions,     /* 4 )聲明 Zend模塊 */  
  29.     PHP_MINIT(hello_module),  
  30.     PHP_MSHUTDOWN(hello_module),  
  31.     PHP_RINIT(hello_module),        /* Replace with NULL if there's nothing to do at request start */  
  32.     PHP_RSHUTDOWN(hello_module),    /* Replace with NULL if there's nothing to do at request end */  
  33.     PHP_MINFO(hello_module),  
  34. #if ZEND_MODULE_API_NO >= 20010901  
  35.     "0.1", /* Replace with version number for your extension */  
  36. #endif  
  37.     STANDARD_MODULE_PROPERTIES  
  38. };  
  39. /* }}} */  
  40.   
  41. /******************  5) 實現get_module()函數 ***********************/  
  42. #ifdef COMPILE_DL_HELLO_MODULE  
  43. ZEND_GET_MODULE(hello_module)  
  44. #endif  
  45.   
  46.   
  47. /* {{{ PHP_INI 
  48.  */  
  49. /* Remove comments and fill if you need to have entries in php.ini 
  50. PHP_INI_BEGIN() 
  51.     STD_PHP_INI_ENTRY("hello_module.global_value",      "42", PHP_INI_ALL, OnUpdateLong, global_value, zend_hello_module_globals, hello_module_globals) 
  52.     STD_PHP_INI_ENTRY("hello_module.global_string", "foobar", PHP_INI_ALL, OnUpdateString, global_string, zend_hello_module_globals, hello_module_globals) 
  53. PHP_INI_END() 
  54. */  
  55. /* }}} */  
  56.   
  57.   
  58. /* {{{ php_hello_module_init_globals 
  59.  */  
  60. /* Uncomment this function if you have INI entries 
  61. static void php_hello_module_init_globals(zend_hello_module_globals *hello_module_globals) 
  62.     hello_module_globals->global_value = 0; 
  63.     hello_module_globals->global_string = NULL; 
  64. */  
  65. /* }}} */  
  66.   
  67.   
  68. /* {{{ PHP_MINIT_FUNCTION 
  69.  */  
  70. PHP_MINIT_FUNCTION(hello_module)  
  71. {  
  72.     /* If you have INI entries, uncomment these lines  
  73.     REGISTER_INI_ENTRIES(); 
  74.     */  
  75.     return SUCCESS;  
  76. }  
  77. /* }}} */  
  78.   
  79.   
  80. /* {{{ PHP_MSHUTDOWN_FUNCTION 
  81.  */  
  82. PHP_MSHUTDOWN_FUNCTION(hello_module)  
  83. {  
  84.     /* uncomment this line if you have INI entries 
  85.     UNREGISTER_INI_ENTRIES(); 
  86.     */  
  87.     return SUCCESS;  
  88. }  
  89. /* }}} */  
  90.   
  91.   
  92. /* Remove if there's nothing to do at request start */  
  93. /* {{{ PHP_RINIT_FUNCTION 
  94.  */  
  95. PHP_RINIT_FUNCTION(hello_module)  
  96. {  
  97.     return SUCCESS;  
  98. }  
  99. /* }}} */  
  100.   
  101.   
  102. /* Remove if there's nothing to do at request end */  
  103. /* {{{ PHP_RSHUTDOWN_FUNCTION 
  104.  */  
  105. PHP_RSHUTDOWN_FUNCTION(hello_module)  
  106. {  
  107.     return SUCCESS;  
  108. }  
  109. /* }}} */  
  110.   
  111.   
  112. /* {{{ PHP_MINFO_FUNCTION 
  113.  */  
  114. PHP_MINFO_FUNCTION(hello_module)  
  115. {  
  116.     php_info_print_table_start();  
  117.     php_info_print_table_header(2, "hello_module support", "enabled");  
  118.     php_info_print_table_end();  
  119.   
  120.   
  121.     /* Remove comments if you have entries in php.ini 
  122.     DISPLAY_INI_ENTRIES(); 
  123.     */  
  124. }  
  125. /* }}} */  
  126.   
  127.   
  128.   
  129.   
  130. /* Remove the following function when you have succesfully modified config.m4 
  131.    so that your module can be compiled into PHP, it exists only for testing 
  132.    purposes. */  
  133.   
  134.   
  135. /* Every user-visible function in PHP should document itself in the source */  
  136. /* {{{ proto string confirm_hello_module_compiled(string arg) 
  137.    Return a string to confirm that the module is compiled in */  
  138. PHP_FUNCTION(confirm_hello_module_compiled)  
  139. {  
  140.     char *arg = NULL;  
  141.     int arg_len, len;  
  142.     char *strg;  
  143.   
  144.   
  145.     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arg_len) == FAILURE) {  
  146.         return;  
  147.     }  
  148.   
  149.   
  150.     len = spprintf(&strg, 0, "Congratulations! You have successfully modified ext/%.78s/config.m4. Module %.78s is now compiled into PHP.", "hello_module", arg);  
  151.     RETURN_STRINGL(strg, len, 0);  
  152. }  
  153. /* }}} */  
  154. /* The previous line is meant for vim and emacs, so it can correctly fold and  
  155.    unfold functions in source code. See the corresponding marks just before  
  156.    function definition, where the functions purpose is also documented. Please  
  157.    follow this convention for the convenience of others editing your code. 
  158. */  
  159.   
  160. /**************************** 6)實現導出函數 *******************************************/  
  161. PHP_FUNCTION(hello_world)   
  162. {    
  163.          RETURN_STRING("HelloWorld", 1);    
  164. }   

模塊結構

全部的 PHP模塊一般都包含如下幾個部分:安全

·        包含頭文件(引入所須要的宏、API定義等)app

·        聲明導出函數(用於 Zend函數塊的聲明)函數

·        聲明 Zend函數塊;優化

·        聲明 Zend模塊;

·        實現get_module()函數;

·        實現導出函數。

1) 包含頭文件

模塊所必須包含的頭文件僅有一個 php.h,它位於 main目錄下。這個文件包含了構建模塊時所必需的各類宏和API定義。

小提示:專門爲模塊建立一個含有其特有信息的頭文件是一個很好的習慣。這個頭文件應該包含 php.h和全部導出函數的定義。若是你是使用 ext_skel來建立模塊的話,那麼你可能已經有了這個文件,由於這個文件會被 ext_skel自動生成。

2)聲明導出函數

爲了聲明導出函數(也就是讓其成爲能夠被 PHP腳本直接調用的原生函數),Zend提供了一個宏來幫助完成這樣一個聲明。代碼以下:

 

  1. ZEND_FUNCTION( hello_world );  

ZEND_FUNCTION 宏聲明瞭一個使用 Zend內部 API來編譯的新的C函數。這個 C函數是 void類型,以 INTERNAL_FUNCTION_PARAMETERS(這是另外一個宏)爲參數,並且函數名字以 zif_爲前綴。把上面這句聲明展開能夠獲得這樣的代碼:

 

  1. void zif_hello_world ( INTERNAL_FUNCTION_PARAMETERS );  

接着再把 INTERNAL_FUNCTION_PARAMETERS展開就會獲得這樣一個結果, 即ZEND_FUNCTION最終擴展結果:

  1. void zif_my_function( int ht    
  2.                    , zval *return_value    
  3.                    , zval *this_ptr    
  4.                    , intreturn_value_used    
  5.                    ,zend_executor_globals * executor_globals    
  6.                    );    

可見,ZEND_FUNCTION就是簡單的聲明瞭一個名爲zif_ first_module的C函數,zif多是」Zend Internal Function」的縮寫。


在解釋器(interpreter)和執行器(executor)被分離出PHP包後,這裏面(指的是解釋器和執行器)原有的一些 API定義及宏也漸漸演變成了一套新的 API系統:Zend API。現在的Zend API 已經承擔了不少原來(指的是分離以前)本屬於 PHP API的職責,大量的 PHP API被以別名的方式簡化爲對應的Zend API。咱們推薦您應該儘量地使用 Zend API,PHP API只是由於兼容性緣由才被保留下來。舉例來講,zval和 pval實際上是同一類型,只不過 zval定義在 Zend部分,而 pval定義在 PHP部分(實際上 pval根本就是 zval的一個別名)。但因爲INTERNAL_FUNCTION_PARAMETERS是一個 Zend宏,所以咱們在上面的聲明中使用了zval。在編寫代碼時,你也應該老是使用 zval以遵循新的 Zend API規範。

這個聲明中的參數列表很是重要,你應該牢記於心。

PHP調用函數的 Zend參數:

參數

說明

ht

這個參數包含了Zend參數的個數。但你不該該直接訪問這個值,而是應該經過 ZEND_NUM_ARGS()宏來獲取參數的個數。

return_value

這個參數用來保存函數向 PHP返回的值。訪問這個變量的最佳方式也是用一系列的宏。後面咱們會有詳細說明。

this_ptr

根據這個參數你能夠訪問該函數所在的對象(換句話說,此時這個函數應該是一個類的方法)。推薦使用函數 getThis()來獲得這個值。

return_value_used

這個值主要用來標識函數的返回值是否爲腳本所使用。0表示腳本不使用其返回值,而 1則相反。一般用於檢驗函數是否被正確調用以及速度優化方面,這是由於返回一個值是一種代價很昂貴的操做(能夠在 array.c裏面看一下是如何利用這一特性的)。

executor_globals

這個變量指向 Zend Engine的全局設置,在建立新變量時這個這個值會頗有用。咱們也能夠函數中使用宏 TSRMLS_FETCH()來引用這個值。

  

3)聲明(引入)Zend(PHP)函數塊

如今你已經聲明瞭導出函數,但Zend並不知道如何調用,所以還必須得將其引入 Zend。這些函數的引入是經過一個包含有N個zend_function_entry結構的數組來完成的。數組的每一項都對應於一個外部可見的函數,每一項都包含了某個函數在 PHP中出現的名字以及在 C代碼中所定義的名字。zend_function_entry的內部聲明:

  1. typedef struct _zend_function_entry {  
  2.     char *fname;  
  3.     void (*handler)(INTERNAL_FUNCTION_PARAMETERS);  
  4.     unsigned char *func_arg_types;  
  5. } zend_function_entry;  

字段

說明

fname

指定在 PHP裏所見到的函數名(好比:fopen、mysql_connect或者是咱們樣例中的hello_world)

handler

指向對應 C函數的句柄。樣例能夠參考前面使用宏INTERNAL_FUNCTION_PARAMETERS的函數聲明。

func_arg_types

用來標識一些參數是否要強制性地按引用方式進行傳遞。一般應將其設定爲 NULL。

對於咱們要建立的模塊:hello_module.該模塊提供一個方法:hello_word,能夠這樣聲明:

  1. const zend_function_entry hello_module_functions[] = {  
  2.      PHP_FE(hello_world, NULL)  
  3.      PHP_FE(confirm_hello_module_compiled, NULL) /* For testing, remove later. */  
  4.      {NULL, NULL, NULL} /* Must be the last line in hello_module_functions[] */  
  5. };  

這樣完成C函數到PHP函數的映射的語句。

你可能已經看到了,這個結構的最後一項是 {NULL, NULL, NULL}。事實上,這個結構的最後一項也必須始終是 {NULL, NULL, NULL},由於 Zend Engine須要靠它來確認這些導出函數的列表是否列舉完畢。

注意:
 1 )你不該該使用一個預約義的宏來代替列表的結尾部分(即{NULL, NULL, NULL}),由於編譯器會盡可能尋找一個名爲 「NULL」 的函數的指針來代替 NULL!
 2)宏 ZEND_FE(「Zend Function Entry」的簡寫)將簡單地展開爲一個zend_function_entry結構。不過須要注意,這些宏對函數採起了一種很特別的命名機制:把你的C函數前加上一個 zif_前綴。比方說,ZEND_FE(hello_word)實際上是指向了一個名爲zif_hello_word()的 C函數。若是你想把宏和一個手工編碼的函數名混合使用時(這並非一個好的習慣),請你務必注意這一點。
小提示:若是出現了一些引用某個名爲zif_*()函數的編譯錯誤,那十有八九與 ZEND_FE 所定義的函數有關。
用來定義函數的宏

說明

ZEND_FE(name, arg_types)

定義了一個zend_function_entry內字段name爲 「name」的函數。arg_types應該被設定爲 NULL。這個聲明須要有一個對應的 C函數,該這個函數的名稱將自動以 zif_爲前綴。舉例來講,ZEND_FE("first_module", NULL)就引入了一個名爲 first_module()的 PHP函數,並被關聯到一個名爲 zif_first_module()的C函數。這個聲明一般與ZEND_FUNCTION搭配使用。

ZEND_NAMED_FE(php_name, name, arg_types)

定義了一個名爲 php_name的 PHP函數,而且被關聯到一個名爲 name的 C函數。arg_types應該被設定爲 NULL。若是你不想使用宏 ZEND_FE自動建立帶有 zif_前綴的函數名的話能夠用這個來代替。一般與ZEND_NAMED_FUNCTION搭配使用。

ZEND_FALIAS(name, alias, arg_types)

爲 name建立一個名爲 alias的別名。arg_types應該被設定爲 NULL。這個聲明不須要有一個對應的 C函數,由於它僅僅是建立了一個用來代替 name的別名而已。

PHP_FE(name, arg_types)

之前的 PHP API,等同於 ZEND_FE。僅爲兼容性而保留,請儘可能避免使用。

PHP_NAMED_FE(runtime_name, name, arg_types)

之前的 PHP API,等同於ZEND_NAMED_FE。僅爲兼容性而保留,請儘可能避免使用。

注意:你不能將 ZEND_FE和 PHP_FUNCTION混合使用,也不能將PHP_FE和 ZEND_FUNCTION混合使用。可是將ZEND_FE+ ZEND_FUNCTION和 PHP_FE + PHP_FUNCTION一塊兒混合使用是沒有任何問題的。固然咱們並不推薦這樣的混合使用,而是建議你所有使用 ZEND_*系列的宏。

4)聲明 Zend模塊

Zend模塊的信息被保存在一個名爲zend_module_entry的結構,它包含了全部須要向 Zend提供的模塊信息。zend_module_entry的內部聲明」中看到這個 Zend模塊的內部定義:

  1. typedef struct _zend_module_entry zend_module_entry;   
  2. struct _zend_module_entry {  
  3. unsigned short size;  
  4. unsigned int zend_api;  
  5. unsigned char zend_debug;  
  6. unsigned char zts;  
  7. char *name;  
  8. zend_function_entry *functions;  
  9. int (*module_startup_func)(INIT_FUNC_ARGS);  
  10. int (*module_shutdown_func)(SHUTDOWN_FUNC_ARGS);  
  11. int (*request_startup_func)(INIT_FUNC_ARGS);  
  12. int (*request_shutdown_func)(SHUTDOWN_FUNC_ARGS);  
  13. void (*info_func)(ZEND_MODULE_INFO_FUNC_ARGS);  
  14. char *version;   
  15. … // 其他的一些咱們不感興趣的信息  
  16. };  

 

字段

說明

size, zend_api, zend_debug and zts

一般用 "STANDARD_MODULE_HEADER"來填充,它指定了模塊的四個成員:標識整個模塊結構大小的 size,值爲 ZEND_MODULE_API_NO常量的 zend_api,標識是否爲調試版本(使用 ZEND_DEBUG進行編譯)的 zend_debug,還有一個用來標識是否啓用了 ZTS(Zend線程安全,使用 ZTS或USING_ZTS進行編譯)的 zts。

name

模塊名稱 (像「File functions」、「Socket functions」、「Crypt」等等).這個名字就是使用phpinfo()函數後在「Additional Modules」部分所顯示的名稱。

functions

Zend 函數塊的指針,這個咱們在前面已經討論過。

module_startup_func

模塊啓動函數。這個函數僅在模塊初始化時被調用,一般用於一些與整個模塊相關初始化的工做(好比申請初始化的內存等等)。若是想代表模塊函數調用失敗或請求初始化失敗請返回 FAILURE,不然請返回 SUCCESS。能夠經過宏 ZEND_MINIT 來聲明一個模塊啓動函數。若是不想使用,請將其設定爲 NULL。

module_shutdown_func

模塊關閉函數。這個函數僅在模塊卸載時被調用,一般用於一些與模塊相關的反初始化的工做(好比釋放已申請的內存等等)。這個函數和module_startup_func()相對應。若是想代表函數調用失敗或請求初始化失敗請返回 FAILURE,不然請返回 SUCCESS。能夠經過宏ZEND_MSHUTDOWN來聲明一個模塊關閉函數。若是不想使用,請將其設定爲 NULL。

request_startup_func

請求啓動函數。這個函數在每次有頁面的請求時被調用,一般用於與該請求相關的的初始化工做。若是想代表函數調用失敗或請求初始化失敗請返回 FAILURE,不然請返回 SUCCESS。注意:若是該模塊是在一個頁面請求中被動態加載的,那麼這個模塊的請求啓動函數將晚於模塊啓動函數的調用(其實這兩個初始化事件是同時發生的)。可使用宏 ZEND_RINIT 來聲明一個請求啓動函數,若不想使用,請將其設定爲 NULL。

request_shutdown_func

請求關閉函數。這個函數在每次頁面請求處理完畢後被調用,正好與request_startup_func()相對應。若是想代表函數調用失敗或請求初始化失敗請返回 FAILURE,不然請返回 SUCCESS。注意:當在頁面請求做爲動態模塊加載時,這個請求關閉函數先於模塊關閉函數的調用(其實這兩個反初始化事件是同時發生的)。可使用宏 ZEND_RSHUTDOWN來聲明這個函數,若不想使用,請將其設定爲NULL。

info_func

模塊信息函數。當腳本調用phpinfo()函數時,Zend便會遍歷全部已加載的模塊,並調用它們的這個函數。每一個模塊都有機會輸出本身的信息。一般狀況下這個函數被用來顯示一些環境變量或靜態信息。可使用宏 ZEND_MINFO來聲明這個函數,若不想使用,請將其設定爲 NULL。

version

模塊的版本號。若是你暫時還不想給某塊設置一個版本號的話,你能夠將其設定爲NO_VERSION_YET。但咱們仍是推薦您在此添加一個字符串做爲其版本號。版本號一般是相似這樣: "2.5-dev", "2.5RC1", "2.5" 或者 "2.5pl3"等等。

Remaining structure elements

這些字段一般是在模塊內部使用的,一般使用宏STANDARD_MODULE_PROPERTIES來填充。並且你也不該該將他們設定別的值。STANDARD_MODULE_PROPERTIES_EX一般只會在你使用了全局啓動函數(ZEND_GINIT)和全局關閉函數(ZEND_GSHUTDOWN)時纔用到,通常狀況請直接使用 STANDARD_MODULE_PROPERTIES 。

在咱們的例子當中,這個結構被定義以下:

 

  1. zend_module_entry hello_module_module_entry = {  
  2. #if ZEND_MODULE_API_NO >= 20010901  
  3.     STANDARD_MODULE_HEADER,  
  4. #endif  
  5.     "hello_module",  
  6.     hello_module_functions,  
  7.     PHP_MINIT(hello_module),  
  8.     PHP_MSHUTDOWN(hello_module),  
  9.     PHP_RINIT(hello_module),        /* Replace with NULL if there's nothing to do at request start */  
  10.     PHP_RSHUTDOWN(hello_module),    /* Replace with NULL if there's nothing to do at request end */  
  11.     PHP_MINFO(hello_module),  
  12. #if ZEND_MODULE_API_NO >= 20010901  
  13.     "0.1", /* Replace with version number for your extension */  
  14. #endif  
  15.     STANDARD_MODULE_PROPERTIES  
  16. };  

這基本上是你能夠設定最簡單、最小的一組值。該模塊名稱爲"hello_module,而後是所引用的函數列表,其後全部的啓動和關閉函數都沒有使用,均被設定爲了

做爲參考,你能夠在表 3 「全部可聲明模塊啓動和關閉函數的宏中找到全部的可設置啓動與關閉函數的宏。這些宏暫時在咱們的例子中還還沒有用到,但稍後咱們將會示範其用法。你應該使用這些宏來聲明啓動和關閉函數,由於它們都須要引入一些特殊的變量(INIT_FUNC_ARGS SHUTDOWN_FUNC_ARGS),而這兩個參數宏將在你使用下面這些預約義宏時被自動引入(其實就是圖個方便)。若是你是手工聲明的函數或是對函數的參數列表做了一些必要的修改,那麼你就應該修改你的模塊相應的源代碼來保持兼容。

3.3全部可聲明模塊啓動和關閉函數的宏

描述

ZEND_MINIT(module)

聲明一個模塊的啓動函數。函數名被自動設定爲zend_minit_<module> (好比:zend_minit_first_module)。一般與ZEND_MINIT_FUNCTION搭配使用。

ZEND_MSHUTDOWN(module)

聲明一個模塊的關閉函數。函數名被自動設定爲zend_mshutdown_<module> (好比:zend_mshutdown_first_module)。一般與ZEND_MSHUTDOWN_FUNCTION搭配使用。

ZEND_RINIT(module)

聲明一個請求的啓動函數。函數名被自動設定爲zend_rinit_<module> (好比:zend_rinit_first_module)。一般與ZEND_RINIT_FUNCTION搭配使用。

ZEND_RSHUTDOWN(module)

聲明一個請求的關閉函數。函數名被自動設定爲zend_rshutdown_<module> (好比:zend_rshutdown_first_module)。一般與ZEND_RSHUTDOWN_FUNCTION搭配使用。

ZEND_MINFO(module)

聲明一個輸出模塊信息的函數,用於phpinfo()。函數名被自動設定爲zend_info_<module> (好比:zend_info_first_module)。一般與ZEND_MINFO_FUNCTION搭配使用。

5) 實現 get_module()函數

這個函數只用於動態可加載模塊。咱們先來看一下如何經過宏ZEND_GET_MODULE來建立這個函數:

  1. #ifdef COMPILE_DL_HELLO_MODULE  
  2. ZEND_GET_MODULE(hello_module)  
  3. #endif  

這個函數的實現被一條件編譯語句所包圍。這是頗有必要的,由於get_module()函數僅僅在你的模塊想要編譯成動態模塊時纔會被調用。經過在編譯命令行指定編譯條件:COMPILE_DL_FIRSTMOD(也就是上面咱們設置的那個預約義)的打開與否,你就能夠決定是編譯成一個動態模塊仍是編譯成一個內建模塊。若是想要編譯成內建模塊的話,那麼這個get_module()將被移除。
get_module()函數在模塊加載時被 Zend所調用,你也能夠認爲是被你 PHP腳本中的dl()函數所調用。這個函數的做用就是把模塊的信息信息塊傳遞 Zend並通知 Zend 獲取這個模塊的相關內容。
若是你沒有在一個動態可加載模塊中實現get_module()函數,那麼當你在訪問它的時候 Zend 就會向你拋出一個錯誤信息。

6)實現導出函數

導出函數的實現是咱們構建擴展的最後一步。在咱們的hello_module例子中,函數被實現以下:

  1. PHP_FUNCTION(hello_world)    
  2. {    
  3.          RETURN_STRING("HelloWorld", 1);    
  4. }   

這個函數是用宏 ZEND_FUNCTION來聲明的,和前面咱們討論的 Zend函數塊中的 ZEND_FE聲明相對應。在函數的聲明以後,咱們的代碼便開始檢查和接收這個函數的參數。在將參數進行轉換後將其值返回。

7)啓動和終止函數

Zend容許模塊在加載和卸載時收到通知,以進行初始化和清除工做,咱們要作的就是把相應函數傳遞給Zend,它會在合適的時機自動調用。

Zend提供了以下四個宏,分別用於聲明對應的函數:

意義

ZEND_MODULE_STARTUP_D(hello_module)

在加載模塊時調用

ZEND_MODULE_SHUTDOWN_D(hello_module)

在卸載模塊時調用

ZEND_MODULE_ACTIVATE_D(hello_module)

一個頁面開始運行時調用

ZEND_MODULE_DEACTIVATE_D(hello_module)

一個頁面運行完畢時調用

 

 

 

 




在聲明模塊信息裏面

  1. zend_module_entry hello_module_module_entry = {  
  2. #if ZEND_MODULE_API_NO >= 20010901  
  3.     STANDARD_MODULE_HEADER,  
  4. #endif  
  5.     "hello_module",  
  6.     hello_module_functions,  
  7.     PHP_MINIT(hello_module),  
  8.     PHP_MSHUTDOWN(hello_module),  
  9.     PHP_RINIT(hello_module),       /* Replace with NULL if there's nothing to do at request start */  
  10.     PHP_RSHUTDOWN(hello_module),    /* Replace with NULL if there's nothing to do at request end */  
  11.     PHP_MINFO(hello_module),  
  12. #if ZEND_MODULE_API_NO >= 20010901  
  13.     "0.1", /* Replace with version number for your extension */  
  14. #endif  
  15.     STANDARD_MODULE_PROPERTIES  
  16. };  

1)STANDARD_MODULE_HEADER和STANDARD_MODULE_PROPERTIES宏填充了該結構的首尾部分,具體填充了什麼並非咱們須要關心的,而且爲了兼容後續版本也最好不要手工修改。
2)第2、三項是模塊名稱和導出函數,名稱能夠任意填寫,導出函數就是咱們在前面準備好的zend_function_entry數組。

3)後面的四個參數內容:

  1.        PHP_MINIT(hello_module),  
  2. PHP_MSHUTDOWN(hello_module),  
  3. PHP_RINIT(hello_module),       /* Replace with NULL if there's nothing to do at request start */  
  4. PHP_RSHUTDOWN(hello_module),    /* Replace with NULL if there's nothing to do at request end */  

就是用於啓動和終止函數,他們都是指針函數。

4) 參數值 PHP_MINFO(hello_module),也是指針函數,用於配合phpinfo()來顯示模塊信息。

這些宏的用法和ZEND_FUNCTION宏同樣,展開後就是聲明瞭特定原型的函數,其參數module能夠是任意的,但最好使用模塊名稱。這些函數的參數中,對咱們有用的是int module_number,它是模塊號,全局惟一,後面會提到其用處。

在聲明和實現相應函數時,都應該使用這些宏。最後,須要把這些函數填寫到zend_module_entry裏,可按順序使用以下的宏,這些宏生成相應的函數名稱:

ZEND_MODULE_STARTUP_N(hello_module)

ZEND_MODULE_SHUTDOWN_N(hello_module)

ZEND_MODULE_ACTIVATE_N(hello_module)

ZEND_MODULE_DEACTIVATE_N(hello_module)

 

 

 




在咱們的hello_module中,對應的聲明(因爲ext_skel生成的代碼是PHP API ,和ZEND API本質上同樣)

  1. PHP_MINIT_FUNCTION(hello_module);  
  2. PHP_MSHUTDOWN_FUNCTION(hello_module);  
  3. PHP_RINIT_FUNCTION(hello_module);  
  4. PHP_RSHUTDOWN_FUNCTION(hello_module);  
  5. PHP_MINFO_FUNCTION(hello_module);  

對應的實現:

  1. /* {{{ PHP_MINIT_FUNCTION 
  2.  */  
  3. PHP_MINIT_FUNCTION(hello_module)  
  4. {  
  5.     /* If you have INI entries, uncomment these lines  
  6.     REGISTER_INI_ENTRIES(); 
  7.     */  
  8.     return SUCCESS;  
  9. }  
  10. /* }}} */  
  11.   
  12. /* {{{ PHP_MSHUTDOWN_FUNCTION 
  13.  */  
  14. PHP_MSHUTDOWN_FUNCTION(hello_module)  
  15. {  
  16.     /* uncomment this line if you have INI entries 
  17.     UNREGISTER_INI_ENTRIES(); 
  18.     */  
  19.     return SUCCESS;  
  20. }  
  21. /* }}} */  
  22.   
  23. /* Remove if there's nothing to do at request start */  
  24. /* {{{ PHP_RINIT_FUNCTION 
  25.  */  
  26. PHP_RINIT_FUNCTION(hello_module)  
  27. {  
  28.     return SUCCESS;  
  29. }  
  30. /* }}} */  
  31.   
  32. /* Remove if there's nothing to do at request end */  
  33. /* {{{ PHP_RSHUTDOWN_FUNCTION 
  34.  */  
  35. PHP_RSHUTDOWN_FUNCTION(hello_module)  
  36. {  
  37.     return SUCCESS;  
  38. }  
  39. /* }}} */  
  40.   
  41. /* {{{ PHP_MINFO_FUNCTION 
  42.  */  
  43. PHP_MINFO_FUNCTION(hello_module)  
  44. {  
  45.     php_info_print_table_start();  
  46.     php_info_print_table_header(2, "hello_module support", "enabled");  
  47.     php_info_print_table_end();  
  48.   
  49.     /* Remove comments if you have entries in php.ini 
  50.     DISPLAY_INI_ENTRIES(); 
  51.     */  
  52. }  
  53. /* }}} */  

若是不想使用這個函數,對應的參數均可以設置爲null

那麼模塊聲明

    1. zend_module_entry hello_module_module_entry = {  
    2. #if ZEND_MODULE_API_NO >= 20010901  
    3.     STANDARD_MODULE_HEADER,  
    4. #endif  
    5.     "hello_module",  
    6.     hello_module_functions,  
    7.     NULL,  
    8.     NULL,  
    9.     NULL,   /* Replace with NULL if there's nothing to do at request start */  
    10.     NULL,   /* Replace with NULL if there's nothing to do at request end */  
    11.     NULL,  
    12. #if ZEND_MODULE_API_NO >= 20010901  
    13.     "0.1", /* Replace with version number for your extension */  
    14. #endif  
    15.     STANDARD_MODULE_PROPERTIES  
    16. }; 
相關文章
相關標籤/搜索