上一文:菜鳥學php擴充 之 hello world ,不問所以然的,強行與php擴展say hello了。對於ext_skel自動產生的框架,將在本文進行詳解,當作備忘錄。
./ext_skel --extname=module [--proto=file] [--stubs=file] [--xml[=file]] [--skel=dir] [--full-xml] [--no-help] --extname=module module is the name of your extension(模块名,会在当前目录创建一个该名称子目录) --proto=file file contains prototypes of functions to create(函数原型定义文件) --stubs=file generate only function stubs in file --xml generate xml documentation to be added to phpdoc-cvs --skel=dir path to the skeleton directory(设置骨架生成的目录,不设置该项则默认在ext/extname下) --full-xml generate xml documentation for a self-contained extension (not yet implemented) --no-help don't try to be nice and create comments in the code and helper functions to test if the module compiled (生成的代码中不显示各种帮助注释)
1.PHP程式的啟動與終止在概念上是分別有兩個的。
一個是php模組載入的時候,模組啟動函數即被引擎呼叫(PHP_MINIT_FUNCTION)。這使得引擎做一些例如資源類型,註冊INI變數等的一次初始化,並且這些資料是常駐記憶體的,與之對應一個終止(PHP_MSHUTDOWN_FUNCTION)
另一個是PHP請求開始的時候,請求前的啟動函數就別呼叫(PHP_RINIT_FUNCTION),與之對應一個請求結束後的終止(PHP_RSHUTDOWN_FUNCTION)
2.伴隨著PHP的啟動,便會開始把自身所有已加載的擴展的MINIT方法(全名為Module Initialization,是由每個模組自己定義的函數。)(PHP_MINIT_FUNCTION),都執行一遍,在這個時間裡,擴展可以定義一些自己的常數、類別、資源等所有會被用戶端的PHP腳本用到的東西。 這裡定義的東東都會常駐內存,可以被所有請求使用,直到關掉PHP模組。
3.一個請求到來時候,PHP會迅速的開闢一個新的環境,並重新掃描自己的各個擴展, 遍歷執行它們各自的RINIT方法(全稱Request Initialization)(PHP_RINIT_FUNCTION), 這時候一個擴充可能會初始化在本次請求中會使用到的變數等, 也會初始化等會兒用戶端(即PHP腳本)中的變數等等。
4.當請求經過業務代碼,執行到最後的時候,PHP會啟動回收程序,會執行所有已加載的擴展的RSHUTDOWN(全稱Request Shutdown)(PHP_RSHUTDOWN_FUNCTION)方法,利用內核中的變量表之類的做一些事情,一旦執行結束,便會釋放掉這次請求使用過的所有東西, 包括變量表的所有變量、所有在這次請求中申請的內存等等
5 .請求處理結束後,該關閉的也關了,PHP便進入MSHUTDOWN(全稱Module Shutdown)(PHP_MSHUTDOWN_FUNCTION)階段,此時PHP會向所有擴展發出最後通牒,如果哪個擴展還有未了的心願,就放在自己MSHUTDOWN方法裡,這可是最後的機會了,一旦PHP把擴展的MSHUTDOWN執行完,便會進入自毀程序。 (清除擅自申請的記憶體的最後機會,否則就記憶體洩漏了)
匯總,我理解的流程:
PHP_MINIT_FUNCTION(一個行程執行一次)
|
執行很多個PHP_RINIT_FUNCTION
|
執行很多個PHP_RSHUTDOWN_FUNCTION
|
PHP_MSHUTDOWN_FUNCTION(一個行程執行一次)
附上多執行緒與多行程的圖
dnl $Id$ dnl config.m4 for extension helloworld dnl Comments in this file start with the string 'dnl'. dnl Remove where necessary. This file will not work dnl without editing. dnl If your extension references something external, use with:##指定PHP模块的工作方式,动态编译选项,如果想通过.so的方式接入扩展,请去掉前面的dnl注释PHP_ARG_WITH(helloworld, for helloworld support, Make sure that the comment is aligned: [ --with-helloworld Include helloworld support]) dnl Otherwise use enable:##指定PHP模块的工作方式,静态编译选项,如果想通过enable的方式来启用,去掉dnl注释PHP_ARG_ENABLE(helloworld, whether to enable helloworld support, Make sure that the comment is aligned: [ --enable-helloworld Enable helloworld support])if test "$PHP_HELLOWORLD" != "no"; then dnl Write more examples of tests here... dnl # --with-helloworld -> check with-path dnl SEARCH_PATH="/usr/local /usr" # you might want to change this dnl SEARCH_FOR="/include/helloworld.h" # you most likely want to change this dnl if test -r $PHP_HELLOWORLD/$SEARCH_FOR; then # path given as parameter dnl HELLOWORLD_DIR=$PHP_HELLOWORLD dnl else # search default path list dnl AC_MSG_CHECKING([for helloworld files in default path]) dnl for i in $SEARCH_PATH ; do dnl if test -r $i/$SEARCH_FOR; then dnl HELLOWORLD_DIR=$i dnl AC_MSG_RESULT(found in $i) dnl fi dnl done dnl fi dnl dnl if test -z "$HELLOWORLD_DIR"; then dnl AC_MSG_RESULT([not found]) dnl AC_MSG_ERROR([Please reinstall the helloworld distribution]) dnl fi dnl # --with-helloworld -> add include path dnl PHP_ADD_INCLUDE($HELLOWORLD_DIR/include) dnl # --with-helloworld -> check for lib and symbol presence dnl LIBNAME=helloworld # you may want to change this dnl LIBSYMBOL=helloworld # you most likely want to change this dnl PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL, dnl [ dnl PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $HELLOWORLD_DIR/$PHP_LIBDIR, HELLOWORLD_SHARED_LIBADD) dnl AC_DEFINE(HAVE_HELLOWORLDLIB,1,[ ]) dnl ],[ dnl AC_MSG_ERROR([wrong helloworld lib version or lib not found]) dnl ],[ dnl -L$HELLOWORLD_DIR/$PHP_LIBDIR -lm dnl ]) dnl ##用于说明这个扩展编译成动态链接库的形式 dnl PHP_SUBST(HELLOWORLD_SHARED_LIBADD) ##用于指定有哪些源文件应该被编译,文件和文件之间用空格隔开 PHP_NEW_EXTENSION(helloworld, helloworld.c, $ext_shared)fi
#define PHP_HELLOWORLD_VERSION "0.1.0"
#ifdef HAVE_CONFIG_H #include "config.h" #endif ##包含头文件(引入所需要的宏、API定义等) #include "php.h" #include "php_ini.h" #include "ext/standard/info.h" #include "php_helloworld.h" static int le_helloworld; ##PHP核心定义的一个宏,与ZEND_FUNCTION相同,用于定义扩展函数(这个函数是系统默认生成的,用于确认之用) PHP_FUNCTION(confirm_helloworld_compiled) { char *arg = NULL; int arg_len, len; char *strg; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arg_len) == FAILURE) { return; } len = spprintf(&strg, 0, "Congratulations! You have successfully modified ext/%.78s/config.m4. Module %.78s is now compiled into PHP.", "helloworld", arg); RETURN_STRINGL(strg, len, 0); } ##定义PHP中可以调用的函数 PHP_FUNCTION(helloworld) { php_printf("Hello World!\n"); RETURN_TRUE; } ##初始化module时运行 PHP_MINIT_FUNCTION(helloworld) { /* If you have INI entries, uncomment these lines REGISTER_INI_ENTRIES(); */ return SUCCESS; } ##当module被卸载时运行 PHP_MSHUTDOWN_FUNCTION(helloworld) { /* uncomment this line if you have INI entries UNREGISTER_INI_ENTRIES(); */ return SUCCESS; } ##当一个REQUEST请求初始化时运行 PHP_RINIT_FUNCTION(helloworld) { return SUCCESS; } ##当一个REQUEST请求结束时运行 PHP_RSHUTDOWN_FUNCTION(helloworld) { return SUCCESS; } ##声明模块信息函数,即可以在phpinfo看到的信息 PHP_MINFO_FUNCTION(helloworld) { php_info_print_table_start(); php_info_print_table_header(2, "helloworld support", "enabled"); php_info_print_table_end(); /* Remove comments if you have entries in php.ini DISPLAY_INI_ENTRIES(); */ } ##声明(引入)Zend(PHP)函数块 const zend_function_entry helloworld_functions[] = { PHP_FE(confirm_helloworld_compiled, NULL) /* For testing, remove later. */ ##上一讲中就是在这里添加了自己定义的函数模块 PHP_FE(helloworld, NULL) /* */ ##zend引擎认为结束的标记,老版本的是“{NULL,NULL,NULL}”,后面PHP源代码直接定义了个宏PHP_FE_END,这里就直接用这个了。虽然都一个意思但看过去爽多了 ##如果遇到PHP_FE_END未定义undefine的问题,请见附录1 PHP_FE_END /* Must be the last line in helloworld_functions[] */ }; ##声明 Zend模块,是不是感觉下面的模块名字很熟悉,对的,就是前文讲到的PHP流程中会用到的,现在懂了为什么要先讲流程了吧~ zend_module_entry helloworld_module_entry = { STANDARD_MODULE_HEADER, "helloworld", helloworld_functions, PHP_MINIT(helloworld), PHP_MSHUTDOWN(helloworld), PHP_RINIT(helloworld), /* Replace with NULL if there's nothing to do at request start */ PHP_RSHUTDOWN(helloworld), /* Replace with NULL if there's nothing to do at request end */ PHP_MINFO(helloworld), PHP_HELLOWORLD_VERSION, STANDARD_MODULE_PROPERTIES }; ##实现get_module()函数 #ifdef COMPILE_DL_HELLOWORLD ZEND_GET_MODULE(helloworld) #endif
PHP_FUNCTION和這個是一樣的有在/main/php.h中已有定義巨集了
#define PHP_FUNCTION ZEND_FUNCTION
这个函数只用于动态可加载模块
6.实现导出函数。
实现想要扩展的函数,PHP_FUNCTION(helloworld)
ps:模块部分是学习这篇文章的,本来写好了,后面发现他写的比我好就借鉴了PHP扩展代码结构详解
1.error: ‘PHP_FE_END’ undeclared here (not in a function)错误。
原因:是因为zend引擎版本太老了。
1、切换到php的源码目录,
2、执行下面两行
# sed -i 's|PHP_FE_END|{NULL,NULL,NULL}|' ./ext/**/*.c # sed -i 's|ZEND_MOD_END|{NULL,NULL,NULL}|' ./ext/**/*.c
3.切换到mcrypt目录,如php-5.x.x/ext/mcrypt/。再次执行make命令,一切恢复正常。
以上是php擴展之擴展框架的自動生成的詳細內容。更多資訊請關注PHP中文網其他相關文章!