<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                ## 擴展開發前言 擴展作用:重新定義PHP行為對PHP進行HACK,提供內部函數或內部類,提升執行性能等 --- ### PHP擴展分類 PHP中的擴展分為兩類:PHP擴展、Zend擴展,對內核而言這兩個分別稱之為:模塊(module)、擴展(extension),我們主要介紹是PHP擴展,也就是模塊. #### 加載區別: * PHP擴展(又名PHP“模塊”)使用“extension = test.so”行加載到INI文件中 * Zend擴展使用“zend_extension = test.so”行加載到INI文件中 Zend擴展比PHP擴展更復雜,因為它們有更多的鉤子,而且更接近Zend引擎及其虛擬機(整個PHP源代碼中最復雜的部分). Zend擴展例子如:OPCache,XDebug,phpdbg,Zend擴展通常用來處理兩種任務:調試器和剖析器.如果您的目標是“只是”向PHP 添加一些新概念(函數,類,常量等),那么您將使用PHP擴展,但如果需要更改PHP的當前行為,可能Zend擴展將會更好. ## PHP擴展生命周期 ![PHP擴展生命周期](https://box.kancloud.cn/7d032a8d3fb47f12b358da564ad9c58f_550x712.png) ```code /* Zend擴展結構 -- zend_extension.h */ struct _zend_extension { ... /* 擴展基礎信息 */ startup_func_t startup; // STARTUP() */ shutdown_func_t shutdown; // SHUTDOWN() 模塊關閉 */ activate_func_t activate; // ACTIVE() 請求啟動 */ */ deactivate_func_t deactivate; // DEACTIVATE() 請求關閉 */ message_handler_func_t message_handler; // MESSAGE_HANDLER() 在擴展注冊后調用 */ op_array_handler_func_t op_array_handler; //在腳本編譯后(zend compilation)后調用的鉤子函數 */ statement_handler_func_t statement_handler; /* */ fcall_begin_handler_func_t fcall_begin_handler; /* 在處理opcode時調用 */ fcall_end_handler_func_t fcall_end_handler; /* */ op_array_ctor_func_t op_array_ctor; /* 構造OPArray時調用 */ op_array_dtor_func_t op_array_dtor; /* 銷毀OPArray時調用 */ int (*api_no_check)(int api_no); /* API_NO_CHECK() 用來檢測擴展是否兼容 */ int (*build_id_check)(const char* build_id); /* BUILD_ID_CHECK() */ ... DL_HANDLE handle; /* dlopen()返回句柄 */ int resource_number; /* 用于管理該擴展名的內部編號 */ }; /* php擴展(模塊)結構 -- zend_modules.h */ struct _zend_module_entry { ... int (*module_startup_func)(INIT_FUNC_ARGS); /* MINIT() 模塊初始化回調函數,通過PHP_MINIT_FUNCTION()或ZEND_MINIT_FUNCTION()宏完成定義 */ int (*module_shutdown_func)(SHUTDOWN_FUNC_ARGS); /* MSHUTDOWN() 模塊關閉階段回調的函數.,通過PHP_MSHUTDOWN_FUNCTION()或ZEND_MSHUTDOWN_FUNCTION()定義, */ int (*request_startup_func)(INIT_FUNC_ARGS); /* RINIT() 請求開始前回調函數,通過PHP_RINIT_FUNCTION()或ZEND_RINIT_FUNCTION()宏定義. */ int (*request_shutdown_func)(SHUTDOWN_FUNC_ARGS); /* RSHUTDOWN() 請求結束時回調函數,通過PHP_RSHUTDOWN_FUNCTION()或ZEND_RSHUTDOWN_FUNCTION()宏定義 */ void (*info_func)(ZEND_MODULE_INFO_FUNC_ARGS); /* PHPINFO() php_info展示的擴展信息處理函數,調用phpinfo()時觸發此函數 */ ... void (*globals_ctor)(void *global); /* GINIT() This funtion is called to initialize a module's globals before any module_startup_func. */ void (*globals_dtor)(void *global); /* GSHUTDOWN() This funtion is called to deallocate a module's globals after any module_shutdown_func. */ int (*post_deactivate_func)(void); /* PRSHUTDOWN() 晚于RSHUTDOWN調用, post-RSHUTDOWN function */ ... }; ``` module_startup/module_shutdown:可用來注冊/銷毀類,全局變量,INI配置,常量 request_startup/request_shutdown:可用來注冊/銷毀特定于每個請求的變量 混合擴展可以注冊為zend擴展或php模塊后,在啟動函數(startup或minit)中再注冊另一個結構. ```c #include "php.h" #include "Zend/zend_extensions.h" #include "php_pib.h" #define PRINT(what) fprintf(stderr, what "\n"); /* Declared as static, thus private */ static zend_module_entry pib_module_entry = { STANDARD_MODULE_HEADER, "pib", NULL, /* Function entries */ PHP_MINIT(pib), /* Module init */ PHP_MSHUTDOWN(pib), /* Module shutdown */ PHP_RINIT(pib), /* Request init */ PHP_RSHUTDOWN(pib), /* Request shutdown */ NULL, /* Module information */ "0.1", /* Replace with version number for your extension */ STANDARD_MODULE_PROPERTIES }; /* This line should stay commented ZEND_GET_MODULE(pib) */ zend_extension_version_info extension_version_info = { ZEND_EXTENSION_API_NO, ZEND_EXTENSION_BUILD_ID }; zend_extension zend_extension_entry = { "pib-zend-extension", "1.0", "PHPInternalsBook Authors", "http://www.phpinternalsbook.com", "Our Copyright", pib_zend_extension_startup, pib_zend_extension_shutdown, pib_zend_extension_activate, pib_zend_extension_deactivate, NULL, NULL, NULL, NULL, NULL, NULL, NULL, STANDARD_ZEND_EXTENSION_PROPERTIES }; static void pib_zend_extension_activate(void) { PRINT("Zend extension new request starting up"); } static void pib_zend_extension_deactivate(void) { PRINT("Zend extension current request is shutting down"); } static int pib_zend_extension_startup(zend_extension *ext) { PRINT("Zend extension is starting up"); /* When the Zend extension part will startup(), make it register a PHP extension by calling ourselves zend_startup_module() */ return zend_startup_module(&pib_module_entry); } static void pib_zend_extension_shutdown(zend_extension *ext) { PRINT("Zend extension is shutting down"); } static PHP_MINIT_FUNCTION(pib) { PRINT("PHP extension is starting up"); return SUCCESS; } static PHP_MSHUTDOWN_FUNCTION(pib) { PRINT("PHP extension is shutting down"); return SUCCESS; } static PHP_RINIT_FUNCTION(pib) { PRINT("PHP extension new request starting up"); return SUCCESS; } static PHP_RSHUTDOWN_FUNCTION(pib) { PRINT("PHP extension current request is shutting down"); return SUCCESS; } ``` #### zend引擎可修改的全局變量函數指針 ```c /* AST, Zend/zend_ast.h: */ void (*zend_ast_process_t)(zend_ast *ast) /* Compiler, Zend/zend_compile.h: */ zend_op_array *(*zend_compile_file)(zend_file_handle *file_handle, int type) zend_op_array *(*zend_compile_string)(zval *source_string, char *filename) /* Executor, Zend/zend_execute.h: */ void (*zend_execute_ex)(zend_execute_data *execute_data) void (*zend_execute_internal)(zend_execute_data *execute_data, zval *return_value) /* GC, Zend/zend_gc.h: */ int (*gc_collect_cycles)(void) /* TSRM, TSRM/TSRM.h: */ void (*tsrm_thread_begin_func_t)(THREAD_T thread_id) void (*tsrm_thread_end_func_t)(THREAD_T thread_id) /* Error, Zend/zend.h: */ void (*zend_error_cb)(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args) /* Exceptions, Zend/zend_exceptions.h: */ void (*zend_throw_exception_hook)(zval *ex) /* Lifetime, Zend/zend.h: */ void (*zend_on_timeout)(int seconds) void (*zend_interrupt_function)(zend_execute_data *execute_data) void (*zend_ticks_function)(int ticks) ``` ## 編碼規則 php-src/CODING_STANDARDS * 用來區別函數行為的數值,除了0,1外,盡量定義為常量. * 用PHP封裝好的函數(emalloc(), efree(), estrdup())分配內存. * 變量名和函數名為小寫字母加下劃線組成,盡量短但不要用縮寫. * 如果是同一父集下的函數,使用parent_*加前綴的命名方法,如(file_get_contents,file_put_contents). * 類名和類中的方法使用駝峰命名法命名,類名首字母大寫,類的方法首字母小寫(如 FooBar->getData() ). * 不要使用`// ...`風格的注釋,使用`/* ... */`格式的注釋。 * 使用tab縮進(四個空格的空間). * 變量聲明和語句塊之間留一個空行, 邏輯語句塊之間也要有空行, 函數與函數之間留一到兩個空行. * 預處理語句(例如 #if)必須寫在第一列,如果要縮進預處理語句也要把 # 號放在一行的開始, 緊接著是任意數量的空格 ## 編譯安裝PHP ```shell make clean ./configure --prefix=/home/ll/workspace/C/php-7-1-8-install --disable-all --enable-cli --enable-debug make -j4 make install ``` #### TODO::擴展的加載,和鉤子函數的調用過程 ## 編寫PHP擴展(模塊)的步驟: 1. 通過ext目錄下ext_skel腳本生成擴展的基本框架:./ext_skel --extname; 2. 修改config.m4配置:設置編譯配置參數、設置擴展的源文件、依賴庫/函數檢查等等; 3. 編寫擴展要實現的功能:按照PHP擴展的格式以及PHP提供的API編寫功能; 4. 生成configure:擴展編寫完成后執行phpize腳本生成configure及其它配置文件; 5. 編譯&安裝:./configure、make、make install,然后將擴展的.so路徑添加到php.ini中. `![PHP擴展的開發過程](https://box.kancloud.cn/275f778ae3e772530fae837ee10a46ae_990x706.jpg)` ## PHP擴展(模塊)生成和編譯 骨架生成器腳本位于php-src/ext/ext_skel中,其使用的模板存儲在 php-src/ext/skeleton ### 基本用法 ```code > php-src/ext/ext_skel ./ext_skel --extname=module [--proto=file] [--stubs=file] [--xml[=file]] [--skel=dir] [--full-xml] [--no-help] --extname=module module為你的擴展名稱 (module is the name of your extension) --proto=file 從file原型文件創建一組PHP函數,方便開發基于庫的擴展.(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) --full-xml generate xml documentation for a self-contained extension (not yet implemented) --no-help 指定此參數會造成 ext_skel 會在生成的文件里省略很多有用的注釋。do not try to be nice and create comments in the code and helper functions to test if the module compiled > php-src/ext/ext_skel --extname=pib > cd php-src/ext > tree pib/ pib/ ├── config.m4 //UNIX 構建系統配置 ├── config.w32 //Windows 構建系統配置 ├── CREDITS //擴展描述文件,包含擴展名,開發者信息。默認生成時只帶有擴展名 ├── EXPERIMENTAL //實驗功能說明 ├── php_pib.h //包含附加的宏、原型和全局量 ├── pib.c //擴展源文件 ├── pib.php //測試文件 └── tests //測試腳本目錄 └── 001.phpt //測試腳本。測試方法:php ../../run-tests.php ./pib/001.phpt (run-tests.php文件存在php源碼根目錄) ``` #### proto原型文件 原型文件有點類似 C 頭文件,根據其中申明的函數,生成函數骨架代碼和其他相關代碼。如 pib.proto,內容為 `string pib_hello_world (string name)` 原型文件的格式,類似于 C 頭文件中的函數申明的方式,返回值、函數名、形參類型、形參名。 參數用 () 包裹,多個參數以 , 分隔,函數申明末尾不需要以 ; 結尾,一行一個函數聲明。 原型文件的生成依賴于 awk 腳本 ext/skeleton/create_stubs ,由其中 convert 函數可知,其支持的參數類型有 ```code int,long bool,boolean double,float string array,object,mixed resource,handle ``` ## 修改config.m4 config.m4是擴展的編譯配置文件,它被include到configure.in文件中,最終被autoconf編譯為configure,編寫擴展時我們只需要在config.m4中修改配置即可. 首先修改 config.m4 ,去掉 PHP_ARG_ENABLE 和 --enable-pib 這兩行前面的 dnl,dnl 是注釋符號。修改后如下 ```code PHP_ARG_ENABLE(pib, whether to enable pib support, dnl Make sure that the comment is aligned: [ --enable-pib Enable pib support]) ``` PHP_ARG_ENABLE函數第一參數表示擴展名,第二個和第三個在生成configure時的一些提示信息。--enable-extname表示不依賴第三方庫,而--with-extname表示需要第三方庫。 PHP_NEW_EXTENSION(pib, pib.c, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1)函數聲明了這個擴展的名稱、需要的源文件名、此擴展的編譯形式。 如果是多個文件的話,就在第二個參數后加空格再填寫你的源文件地址,需要換行的話記得反斜杠\。 ### config.m4常用宏 PHP在acinclude.m4中基于autoconf/automake的宏封裝了很多可以直接使用的宏,下面介紹幾個比較常用的宏: * `PHP_ARG_WITH(arg_name,check message,help info)`: 定義一個--with-feature[=arg]這樣的編譯參數,調用的是autoconf的AC_ARG_WITH,這個宏有5個參數,常用的是前三個,分別表示:參數名、執行./configure是展示信息、執行--help時展示信息,第4個參數為默認值,如果不定義默認為"no",通過這個宏定義的參數可以在config.m4中通過$PHP_參數名(大寫)訪問.比如:PHP_ARG_WITH(aaa, aaa-configure, help aa)后面通過$PHP_AAA就可以讀取到--with-aaa=xxx設置的值了 * `PHP_ARG_ENABLE(arg_name,check message,help info)`: 定義一個--enable-feature[=arg]或--disable-feature參數,--disable-feature等價于--enable-feature=no,這個宏與PHP_ARG_WITH類似,通常情況下如果配置的參數需要額外的arg值會使用PHP_ARG_WITH,而如果不需要arg值,只用于開關配置則會使用PHP_ARG_ENABLE. * `AC_MSG_CHECKING()/AC_MSG_RESULT()/AC_MSG_ERROR()`: ./configure時輸出結果,其中error將會中斷configure執行. * `AC_DEFINE(variable, value, [description])`: 定義一個宏,比如:AC_DEFINE(IS_DEBUG, 1, []),執行autoheader時將在頭文件中生成:#define IS_DEBUG 1. * `PHP_ADD_INCLUDE(path)`: 添加include路徑,即:gcc -Iinclude_dir,#include "file";將先在通過-I指定的目錄下查找,擴展引用了外部庫或者擴展下分了多個目錄的情況下會用到這個宏. * `PHP_CHECK_LIBRARY(library, function [, action-found [, action-not-found [, extra-libs]]])`: 檢查依賴的庫中是否存在需要的function,action-found為存在時執行的動作,action-not-found為不存在時執行的動作,比如擴展里使用到線程pthread,檢查pthread_create(),如果沒找到則終止./configure執行: ```code PHP_ADD_INCLUDE(pthread, pthread_create, [], [ AC_MSG_ERROR([not find pthread_create() in lib pthread]) ]) ``` * `AC_CHECK_FUNC(function, [action-if-found], [action-if-not-found])`: 檢查函數是否存在. (8)PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $XXX_DIR/$PHP_LIBDIR, XXX_SHARED_LIBADD): 添加鏈接庫. * `PHP_NEW_EXTENSION(extname, sources [, shared [, sapi_class [, extra-cflags [, cxx [, zend_ext]]]]])`: 注冊一個擴展,添加擴展源文件,確定此擴展是動態庫還是靜態庫,每個擴展的config.m4中都需要通過這個宏完成擴展的編譯配置. 更多autoconf及PHP封裝的宏大家可以在用到的時候再自行檢索,同時ext目錄下有大量的示例可供參考. [參考鏈接](https://secure.php.net/manual/en/internals2.buildsys.configunix.php) ## 編譯安裝測試擴展 ```shell cd ext/pib ../../../php-7-1-8-install/bin/phpize ./configure --with-php-config=../../../php-7-1-8-install/bin/php-config make cd ../../sapi/cli ./php -d extension='../../ext/pib/modules/pib.so' -r "echo confirm_pib_compiled('hello world');" ``` 在擴展目錄(ext/pib/)中,phpize會根據config.m4生一個configure文件. 執行./configure后會生makefiles文件,再執行make . 然后擴展中modules目錄下會發現一個pib.so文件 . make install 會將擴展復制到PHP安裝路徑的擴展目錄當中 。 測試會輸出Congratulations! You have successfully modified ext/pib/config.m4. Module hello world is now compiled into PHP. ### 發布前執行 `phpize --clean` ## 參考資料: http://www.phpinternalsbook.com/index.html https://github.com/pangudashu/php7-internal/ https://secure.php.net/manual/en/internals2.structure.php http://www.laruence.com/2009/04/28/719.html https://andot.gitbooks.io/bped/c02s03.html https://github.com/lxy254069025/php-extension-book http://php.net/manual/zh/internals2.buildsys.configunix.php http://www.php-internals.com/book/?p=chapt11/11-02-00-extension-hello-world
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看