<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國際加速解決方案。 廣告
                ## PHP擴展(模塊)結構 ### zend_module_struct 擴展首先需要創建一個zend_module_entry結構,這個變量必須是全局變量,且變量名必須是:擴展名稱_module_entry,內核通過這個結構得到這個擴展都提供了哪些功能 ```c /* zend_modules.h */ /* 參考:https://secure.php.net/manual/en/internals2.structure.modstruct.php */ struct _zend_module_entry { unsigned short size; /* sizeof(zend_module_entry) */ unsigned int zend_api; /* ZEND_MODULE_API_NO */ /* STANDARD_MODULE_HEADER */ unsigned char zend_debug; /* 是否開啟debug */ unsigned char zts; /* 是否開啟線程安全 */ const struct _zend_ini_entry *ini_entry; /* 未使用 */ const struct _zend_module_dep *deps; /* 擴展依賴 */ const char *name; /* 擴展名稱,不能重復 */ const struct _zend_function_entry *functions; /* 擴展提供的內部函數列表 */ int (*module_startup_func)(INIT_FUNC_ARGS); /* 擴展初始化回調函數,PHP_MINIT_FUNCTION或ZEND_MINIT_FUNCTION定義的函數 */ int (*module_shutdown_func)(SHUTDOWN_FUNC_ARGS); /* 擴展關閉時回調函數 */ int (*request_startup_func)(INIT_FUNC_ARGS); /* 請求開始前回調函數 */ int (*request_shutdown_func)(SHUTDOWN_FUNC_ARGS); /* 請求結束時回調函數 */ void (*info_func)(ZEND_MODULE_INFO_FUNC_ARGS); /* php_info展示的擴展信息處理函數 */ const char *version; /* 版本 */ //STANDARD_MODULE_PROPERTIES size_t globals_size; /* */ #ifdef ZTS /* */ ts_rsrc_id* globals_id_ptr; /* */ #else /* */ /* Globals management */ void* globals_ptr; /* */ #endif /* */ void (*globals_ctor)(void *global); /* */ void (*globals_dtor)(void *global); /* */ /* */ int (*post_deactivate_func)(void); /* Rarely used lifetime hook */ int module_started; /* 擴展已啟動(內部使用) */ unsigned char type; /* 擴展類型(內部使用) */ /* STANDARD_MODULE_PROPERTIES_EX */ void *handle; /* dlopen()返回句柄 */ int module_number; /* 擴展的唯一編號 */ const char *build_id; /* build id,STANDARD_MODULE_PROPERTIES_EX */ }; ``` ```c zend_module_entry pib_module_entry = { STANDARD_MODULE_HEADER, "pib", pib_functions, PHP_MINIT(pib), PHP_MSHUTDOWN(pib), PHP_RINIT(pib), /* Replace with NULL if there's nothing to do at request start */ PHP_RSHUTDOWN(pib), /* Replace with NULL if there's nothing to do at request end */ PHP_MINFO(pib), PHP_PIB_VERSION, STANDARD_MODULE_PROPERTIES }; ``` ### 發布 PHP編譯時默認將所有符號隱藏,所以要獲取擴展必須使用ZEND_GET_MODULE(your_ext)宏,會在頭文件中有定義`PHP_<EXT-NAME>_API`. PHP在啟動時會調用每個擴展中的get_module()函數,函數在頭主文件`php_<your-ext-name>.c`(這里是 pib.c)中 ```c #ifdef COMPILE_DL_PIB #ifdef ZTS ZEND_TSRMLS_CACHE_DEFINE() #endif ZEND_GET_MODULE(pib) #endif ``` 模塊符號是在這里發布,當編譯時加上`–enable-<my-ext-name>`時,`COMPILE_DL_<YOUR-EXT-NAME>`將被定義.模塊被加載. ### 發布API 在頭文件`php_<your-ext-name>.h`(這里是 php_pib.h)中 ```c #ifdef PHP_WIN32 # define PHP_PIB_API __declspec(dllexport) #elif defined(__GNUC__) && __GNUC__ >= 4 # define PHP_PIB_API __attribute__ ((visibility("default"))) #else # define PHP_PIB_API #endif ``` 使用`PHP_<EXT-NAME>_API` (這里是PHP_PIB_API)宏將設置為公開,使其在其它擴展中可用. ## 定義全局變量 ```c /* php_pib.h */ #define PIB_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(pib, v) /* 定義一個宏用于訪問擴展的全局資源結構體 */ ZEND_BEGIN_MODULE_GLOBALS(pib)/* 展開后實際就是個普通的struct聲明 */ zend_long open_cache; HashTable class_table; ZEND_END_MODULE_GLOBALS(pib) /* pib.c */ ZEND_DECLARE_MODULE_GLOBALS(pib) /* 創建一個此結構體的全局變量,會根據是否開啟線程安全采用不同方式 */ ``` 接下來就可以在擴展中通過:PIB_G(opene_cache)、PIB_G(class_table)對結構體成員進行讀寫了. ## 注冊函數 ### zend_function_entry用于在擴展中注冊函數到zend引擎 由擴展名聲明的函數稱為“內部”函數,與PHP用戶定義的函??數相反,內部函數在當前請求結束時不會反注冊直到PHP退出. ```c #define INTERNAL_FUNCTION_PARAMETERS zend_execute_data *execute_data, zval *return_value typedef struct _zend_function_entry { const char *fname; /* 函數名 */ void (*handler)(INTERNAL_FUNCTION_PARAMETERS); /* 處理程序 */ const struct _zend_internal_arg_info *arg_info; /* 參數,推薦使用宏定義. */ uint32_t num_args; /* 參數個數 */ uint32_t flags; /* 函數標記 */ } zend_function_entry; struct _zend_module_entry { ... const struct _zend_function_entry *functions; /* 函數定義聲明 */ ... /* ... */ }; ``` ### 一個簡單聲明定義示例 ```c /* pib.c */ PHP_FUNCTION(fahrenheit_to_celsius) { } static const zend_function_entry pib_functions[] = { PHP_FE(fahrenheit_to_celsius, NULL) PHP_FE_END /* 末尾必須加這個 */ } zend_module_entry pib_module_entry = { STANDARD_MODULE_HEADER, "pib", pib_functions, NULL, NULL, NULL, NULL, NULL, "0.1", STANDARD_MODULE_PROPERTIES }; /* 函數定義聲明宏展開為: */ void zif_fahrenheit_to_celsius(zend_execute_data *execute_data, zval *return_value) { } static const zend_function_entry pib_functions[] = { { "fahrenheit_to_celsius", zif_fahrenheit_to_celsius, ((void *)0), (uint32_t) (sizeof(((void *)0))/sizeof(struct _zend_internal_arg_info)-1), 0 }, } /* 展開后的函數句加上了'zif'前綴,代表 Zend內部函數,以防止名稱沖突. */ ``` 通過使用PHP_FUNCTION()宏來定義函數,同時在php_pib.h頭文件里聲明這個函數: ```c /* pib.h */ PHP_FUNCTION (fahrenheit_to_celsius); ``` 查看擴展的反射信息 ```shell /php/bin/php -dextension=pib.so --re pib ``` ### 函數參數和返回值 #### 參數聲明 參數聲明不是強制性的,但高度推薦.反射API(reflection API)使用參數聲明來獲取有關該功能的信息. 參數聲明的數據結構 ```c typedef struct _zend_internal_arg_info { const char *name; /* 參數名 */ const char *class_name; zend_uchar type_hint; /* 顯式聲明的類型 */ zend_uchar pass_by_reference; /* 是否引用傳參 */ zend_bool allow_null; /* 是否允許參數為NULL,類似"!"的用法 */ zend_bool is_variadic; /* 是否為可變參數 */ } zend_internal_arg_info; /* 使用宏定義參數(如果你不知道如何命名參數矢量符號,一個實踐是使用 'arginfo_[function name]'模式): */ ZEND_BEGIN_ARG_INFO_EX(arginfo_fahrenheit_to_celsius, 0, 0, 1) ZEND_ARG_INFO(0, fahrenheit) ZEND_END_ARG_INFO(); /* 宏展開后 */ static const zend_internal_arg_info arginfo_fahrenheit_to_celsius[] = { { (const char*)(zend_uintptr_t)(1), ((void *)0), 0, 0, 0, 0 }, { "fahrenheit", ((void *)0), 0, 0, 0, 0 }, }; /* 聲明參數相關宏,宏定義位置:Zend/zend_API.h: */ /* name: 參數數組名,注冊函數PHP_FE(function, arg_info)會用到 _unused: 保留值,暫時無用 return_reference: 返回值是否為引用,一般很少會用到 required_num_args: required參數數 */ ZEND_BEGIN_ARG_INFO_EX(name, _unused, return_reference, required_num_args); /* pass_by_ref表示是否引用傳參,name為參數名稱 */ #define ZEND_ARG_INFO(pass_by_ref, name) { #name, NULL, 0, pass_by_ref, 0, 0 }, /* 只聲明此參數為引用傳參 */ #define ZEND_ARG_PASS_INFO(pass_by_ref) { NULL, NULL, 0, pass_by_ref, 0, 0 }, /* 顯式聲明此參數的類型為指定類的對象,等價于PHP中這樣聲明:MyClass $obj */ #define ZEND_ARG_OBJ_INFO(pass_by_ref, name, classname, allow_null) { #name, #classname, IS_OBJECT, pass_by_ref, allow_null, 0 }, /* 顯式聲明此參數類型為數組,等價于:array $arr */ #define ZEND_ARG_ARRAY_INFO(pass_by_ref, name, allow_null) { #name, NULL, IS_ARRAY, pass_by_ref, allow_null, 0 }, /* 顯式聲明為callable,將檢查函數、成員方法是否可調 */ #define ZEND_ARG_CALLABLE_INFO(pass_by_ref, name, allow_null) { #name, NULL, IS_CALLABLE, pass_by_ref, allow_null, 0 }, /* 通用宏,自定義各個字段 */ #define ZEND_ARG_TYPE_INFO(pass_by_ref, name, type_hint, allow_null) { #name, NULL, type_hint, pass_by_ref, allow_null, 0 }, /* 聲明為可變參數 */ #define ZEND_ARG_VARIADIC_INFO(pass_by_ref, name) { #name, NULL, 0, pass_by_ref, 0, 1 }, ``` ```c /* 這個參數數組聲明完成后,我們需要將arginfo_fahrenheit_to_celsius添加到函數聲明當中 */ PHP_FE(fahrenheit_to_celsius, arginfo_fahrenheit_to_celsius) ``` #### 解析參數:zend_parse_parameters() zend_parse_parameters()是將參數讀取到Zend引擎棧的函數.你會告訴你要讀取多少參數,以及你想要為你提供什么樣的類型.該函數將根據PHP類型轉換規則將參數轉換為您要求的類型. 如果你使用zend_parse_parameters來接收參數,那么你是不需要ZEND_BEGIN_ARG_INFO_EX宏來進行入參數校驗的。但如果使用的是zend_get_parameters那么就需要zend幫你自動校驗了。記得在PHP_FE中加入校驗名。 函數參數是從PHP用戶空間傳到函數的,它們與用戶自定義函數完全相同,包括參數的分配方式、傳參過程,也是按照參數次序依次分配在運行棧幀上,所以在擴展中定義的函數直接按照順序從運行棧幀上讀取對應的值即可,PHP中通過zend_parse_parameters()這個函數解析運行棧幀上保存的參數 `zend_parse_parameters(int num_args, const char *type_spec, ...);` 第一個參數是給出運行時的參數數,通過ZEND_NUM_ARGS()獲取:zend_execute_data->This.u2.num_args,前面曾介紹過zend_execute_data->This這個zval的用途. 然后我們傳遞一個“d”字符,表示要接收的每一個參數類型為double類型.zend引擎將讀取到的參數寫入到變量c當中. 解析參數時傳遞的字符規則在源碼目錄里的README.PARAMETER_PARSING_API文件中. 解析的過程就是按照type_spec指定的各個類型,依次從zend_execute_data上獲取參數,然后將參數地址賦給目標變量. ```c static double php_fahrenheit_to_celsius(double f) { return ((double)5/9) * (double)(f - 32); } PHP_FUNCTION(fahrenheit_to_celsius) { double f; /* 在php7中,提供另一種獲取參數的方式FAST_ZPP(Fast zend parameter parsing),是為了提高參數解析的性能。 */ #ifdef FAST_ZPP ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_DOUBLE(f) /* zend_API.h */ ZEND_PARSE_PARAMETERS_END(); #else if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &f) == FAILURE) { return; } #endif /* 使用RETURN_***()宏,設置返回值并返回 */ RETURN_DOUBLE(php_fahrenheit_to_celsius(f)); /* #define RETURN_DOUBLE(d) { RETVAL_DOUBLE(d); return; } */ } ``` ##### 返回值相關宏 ```c /* 返回布爾型,b:IS_FALSE、IS_TRUE */ #define RETURN_BOOL(b) { RETVAL_BOOL(b); return; } /* 返回NULL */ #define RETURN_NULL() { RETVAL_NULL(); return;} /* 返回整形,l類型:zend_long */ #define RETURN_LONG(l) { RETVAL_LONG(l); return; } /* 返回浮點值,d類型:double */ #define RETURN_DOUBLE(d) { RETVAL_DOUBLE(d); return; } /* 返回字符串,可返回內部字符串,s類型為:zend_string * */ #define RETURN_STR(s) { RETVAL_STR(s); return; } /* 返回內部字符串,這種變量將不會被回收,s類型為:zend_string * */ #define RETURN_INTERNED_STR(s) { RETVAL_INTERNED_STR(s); return; } /* 返回普通字符串,非內部字符串,s類型為:zend_string * */ #define RETURN_NEW_STR(s) { RETVAL_NEW_STR(s); return; } /* 拷貝字符串用于返回,這個會自己加引用計數,s類型為:zend_string * */ #define RETURN_STR_COPY(s) { RETVAL_STR_COPY(s); return; } /* 返回char *類型的字符串,s類型為char * */ #define RETURN_STRING(s) { RETVAL_STRING(s); return; } /* 返回char *類型的字符串,s類型為char *,l為字符串長度,類型為size_t */ #define RETURN_STRINGL(s, l) { RETVAL_STRINGL(s, l); return; } /* 返回空字符串 */ #define RETURN_EMPTY_STRING() { RETVAL_EMPTY_STRING(); return; } /* 返回資源,r類型:zend_resource * */ #define RETURN_RES(r) { RETVAL_RES(r); return; } /* 返回數組,r類型:zend_array * */ #define RETURN_ARR(r) { RETVAL_ARR(r); return; } /* 返回對象,r類型:zend_object * */ #define RETURN_OBJ(r) { RETVAL_OBJ(r); return; } /* 返回zval */ #define RETURN_ZVAL(zv, copy, dtor) { RETVAL_ZVAL(zv, copy, dtor); return; } /* 返回false */ #define RETURN_FALSE { RETVAL_FALSE; return; } /* 返回true */ #define RETURN_TRUE { RETVAL_TRUE; return; } ``` #### 傳遞引用參數,修改上面代碼: ```c ZEND_BEGIN_ARG_INFO_EX(arginfo_fahrenheit_to_celsius, 0, 0, 1) /* 這里1表示通知引擎必須通過引用傳遞該參數 */ ZEND_ARG_INFO(1, fahrenheit) ZEND_END_ARG_INFO(); /* 當我們收到參數時,我們使用“z”參數類型,告訴我們要將其賦予zval *,接收到的zval為將是IS_REFERENCE類型,我們需要取消引用然后修改. */ PHP_FUNCTION(fahrenheit_to_celsius) { double result; zval *param; if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &param) == FAILURE) { return; } ZVAL_DEREF(param); convert_to_double(param); ZVAL_DOUBLE(param, php_fahrenheit_to_celsius(Z_DVAL_P(param))); } /* a reference (by that we mean a &$php_reference) is a heap allocated zval stored into a zval container */ /* 引用(&$php_var)是在堆中分配的zval然后存儲在了zval容器中. */ ``` ## ini配置 擴展中一般會把php.ini配置映射前面介紹的全局變量(資源) ```c PHP_INI_BEGIN() /* 將php.ini中的pib.opene_cache值映射到PIB_G()結構中的open_cache,類型為zend_long,默認值109,則可以這么定義: */ STD_PHP_INI_ENTRY("pib.open_cache", "109", PHP_INI_ALL, OnUpdateLong, open_cache, zend_pib_globals, pib_globals) /* 其它規則 */ ... PHP_INI_END(); /* 上面的定義展開后: */ static const zend_ini_entry_def ini_entries[] = { { "pib.open_cache", OnUpdateLong, (void *) XtOffsetOf(zend_pib_globals, open_cache), //XtOffsetOf這個宏在linux環境下展開就是offsetof(),用來獲取一個結構體成員的offset (void*)&pib_globals, NULL, "109", NULL, PHP_INI_ALL, sizeof("pib.open_cache")-1, sizeof("109")-1 }, { NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0} } /* STD_PHP_INI_ENTRY(name,default_value,modifiable,on_modify,property_name,struct_type,struct_ptr) name: php.ini中的配置標識符 default_value: 默認值,注意不管轉化后是什么類型,這里必須設置為字符串 modifiable: 可修改等級,ZEND_INI_USER為可以在php腳本中修改,ZEND_INI_SYSTEM為可以在php.ini中修改,還有一個ZEND_INI_PERDIR,ZEND_INI_ALL表示三種都可以,通常情況下設置為ZEND_INI_ALL、ZEND_INI_SYSTEM即可 on_modify: 函數指針,用于指定發現這個配置后賦值處理的函數,默認提供了5個:OnUpdateBool、OnUpdateLong、OnUpdateLongGEZero、OnUpdateReal、OnUpdateString、OnUpdateStringUnempty,支持可以自定義 property_name: 要映射到的結構struct_type中的成員 struct_type: 映射結構的類型 struct_ptr: 映射結構的變量地址 這個宏展開后生成一個zend_ini_entry_def結構: typedef struct _zend_ini_entry_def { const char *name; int (*on_modify)(zend_ini_entry *entry, zend_string *new_value, void *mh_arg1, void *mh_arg2, void *mh_arg3, int stage); void *mh_arg1; //映射成員所在結構體的偏移:offsetof(type, member-designator)取到 void *mh_arg2; //要映射到結構的地址 void *mh_arg3; const char *value;//默認值 void (*displayer)(zend_ini_entry *ini_entry, int type); int modifiable; uint name_length; uint value_length; } zend_ini_entry_def; */ ``` #### 將ini配置注冊到全局變量: ```c /* php_pib.h */ #define PIB_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(pib, v) ZEND_BEGIN_MODULE_GLOBALS(pib) zend_long open_cache; ZEND_END_MODULE_GLOBALS(pib) /* pib.c */ ZEND_DECLARE_MODULE_GLOBALS(pib) PHP_INI_BEGIN() STD_PHP_INI_ENTRY("pib.open_cache", "109", PHP_INI_ALL, OnUpdateLong, open_cache, zend_pib_globals, pib_globals) PHP_INI_END(); PHP_MINIT_FUNCTION(pib) { REGISTER_INI_ENTRIES(); return SUCCESS; } PHP_MSHUTDOWN_FUNCTION(pib) { UNREGISTER_INI_ENTRIES(); return SUCCESS; } zend_module_entry pib_module_entry = { STANDARD_MODULE_HEADER, "pib", NULL,//pib_functions, PHP_MINIT(pib), PHP_MSHUTDOWN(pib), NULL,//PHP_RINIT(pib), NULL,//PHP_RSHUTDOWN(pib), NULL,//PHP_MINFO(pib), "1.0.0", STANDARD_MODULE_PROPERTIES }; ``` #### ini聲明和讀取: ```c /* hello.c */ PHP_INI_BEGIN() PHP_INI_ENTRY("hello.yell", "0", PHP_INI_ALL, NULL) PHP_INI_END() PHP_MINIT_FUNCTION(hello) { REGISTER_INI_ENTRIES(); return SUCCESS; } PHP_MSHUTDOWN_FUNCTION(hello) { UNREGISTER_INI_ENTRIES(); return SUCCESS; } /* function hello(string $name): bool */ PHP_FUNCTION(hello) { int i = 0; zend_string *name; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STR(name) ZEND_PARSE_PARAMETERS_END(); if (INI_BOOL("hello.yell") == 1) { while (name->val[i]) { name->val[i] = toupper(name->val[i]); i++; } php_printf("HELLO %s!\n", ZSTR_VAL(name)); } else { php_printf("Hello %s\n", ZSTR_VAL(name)); } RETURN_TRUE; } zend_module_entry hello_module_entry = { STANDARD_MODULE_HEADER, PHP_HELLO_EXTNAME, hello_functions, /* Function entries */ PHP_MINIT(hello), /* Module init */ PHP_MSHUTDOWN(hello), /* Module shutdown */ NULL, /* Request init */ NULL, /* Request shutdown */ NULL, /* Module information */ PHP_HELLO_VERSION, STANDARD_MODULE_PROPERTIES }; ``` ## 參考資料: http://www.phpinternalsbook.com/index.html https://github.com/pangudashu/php7-internal/ https://secure.php.net/manual/en/internals2.structure.php https://secure.php.net/manual/en/internals2.funcs.php http://www.cunmou.com/phpbook/7.2.md
                  <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>

                              哎呀哎呀视频在线观看