<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>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                ## 7.2 擴展的實現原理 PHP中擴展通過`zend_module_entry`這個結構來表示,此結構定義了擴展的全部信息:擴展名、擴展版本、擴展提供的函數列表以及PHP四個執行階段的hook函數等,每一個擴展都需要定義一個此結構的變量,而且這個變量的名稱格式必須是:`{module_name}_module_entry`,內核正是通過這個結構獲取到擴展提供的功能的。 擴展可以在編譯PHP時一起編譯(靜態編譯),也可以單獨編譯為動態庫,動態庫需要加入到php.ini配置中去,然后在`php_module_startup()`階段把這些動態庫加載到PHP中: ```c int php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_modules, uint num_additional_modules) { ... //根據php.ini注冊擴展 php_ini_register_extensions(); zend_startup_modules(); zend_startup_extensions(); ... } ``` 動態庫就是在`php_ini_register_extensions()`這個函數中完成的注冊: ```c //main/php_ini.c void php_ini_register_extensions(void) { //注冊zend擴展 zend_llist_apply(&extension_lists.engine, php_load_zend_extension_cb); //注冊php擴展 zend_llist_apply(&extension_lists.functions, php_load_php_extension_cb); zend_llist_destroy(&extension_lists.engine); zend_llist_destroy(&extension_lists.functions); } ``` extension_lists是一個鏈表,保存著根據`php.ini`中定義的`extension=xxx.so`取到的全部擴展名稱,其中engine是zend擴展,functions為php擴展,依次遍歷這兩個數組然后調用`php_load_php_extension_cb()`或`php_load_zend_extension_cb()`進行各個擴展的加載: ```c static void php_load_php_extension_cb(void *arg) { #ifdef HAVE_LIBDL php_load_extension(*((char **) arg), MODULE_PERSISTENT, 0); #endif } ``` `HAVE_LIBDL`這個宏根據`dlopen()`函數是否存在設置的: ```sh #Zend/Zend.m4 AC_DEFUN([LIBZEND_LIBDL_CHECKS],[ AC_CHECK_LIB(dl, dlopen, [LIBS="-ldl $LIBS"]) AC_CHECK_FUNC(dlopen,[AC_DEFINE(HAVE_LIBDL, 1,[ ])]) ]) ``` 接著就是最關鍵的操作了,`php_load_extension()`: ```c //ext/standard/dl.c PHPAPI int php_load_extension(char *filename, int type, int start_now) { void *handle; char *libpath; zend_module_entry *module_entry; zend_module_entry *(*get_module)(void); ... //調用dlopen打開指定的動態連接庫文件:xx.so handle = DL_LOAD(libpath); ... //調用dlsym獲取get_module的函數指針 get_module = (zend_module_entry *(*)(void)) DL_FETCH_SYMBOL(handle, "get_module"); ... //調用擴展的get_module()函數 module_entry = get_module(); ... //檢查擴展使用的zend api是否與當前php版本一致 if (module_entry->zend_api != ZEND_MODULE_API_NO) { DL_UNLOAD(handle); return FAILURE; } ... module_entry->type = type; //為擴展編號 module_entry->module_number = zend_next_free_module(); module_entry->handle = handle; if ((module_entry = zend_register_module_ex(module_entry)) == NULL) { DL_UNLOAD(handle); return FAILURE; } ... } ``` `DL_LOAD()`、`DL_FETCH_SYMBOL()`這兩個宏在linux下展開后就是:dlopen()、dlsym(),所以上面過程的實現就比較直觀了: * (1)dlopen()打開so庫文件; * (2)dlsym()獲取動態庫中`get_module()`函數的地址,`get_module()`是每個擴展都必須提供的一個接口,用于返回擴展`zend_module_entry`結構的地址; * (3)調用擴展的`get_module()`,獲取擴展的`zend_module_entry`結構; * (4)zend api版本號檢查,比如php7的擴展在php5下是無法使用的; * (5)注冊擴展,將擴展添加到`module_registry`中,這是一個全局HashTable,用于全部擴展的zend_module_entry結構; * (6)如果擴展提供了內部函數則將這些函數注冊到EG(function_table)中。 完成擴展的注冊后,PHP將在不同的執行階段依次調用每個擴展注冊的當前階段的hook函數。
                  <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>

                              哎呀哎呀视频在线观看