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

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                ### 定義函數 函數會被注冊到EG(function_table),函數被調用時根據函數名稱在這個符號表中查找 內部函數即由C實現邏輯的函數,可以直接供php調用,用戶函數是指PHP腳本中用戶自定義函數; 內部函數結構如下: ```c typedef struct _zend_internal_function { /* Common elements */ zend_uchar type; zend_uchar arg_flags[3]; /* bitset of arg_info.pass_by_reference */ uint32_t fn_flags; zend_string* function_name; zend_class_entry *scope; zend_function *prototype; uint32_t num_args; uint32_t required_num_args; zend_internal_arg_info *arg_info; /* END of common elements */ void (*handler)(INTERNAL_FUNCTION_PARAMETERS); //函數指針,展開:void (*handler)(zend_execute_data *execute_data, zval *return_value) struct _zend_module_entry *module; void *reserved[ZEND_MAX_RESERVED_RESOURCES]; } zend_internal_function; ``` 主要關注的是handler,handler是一個函數指針,由PHP_FUNCTION定義,例如: ```c // hello.c PHP_FUNCTION(helloworld) { zend_string *strg; strg = strpprintf(0, "hello world \n"); RETURN_STR(strg); } ``` 宏定義: ```c // main/php.h #define PHP_FUNCTION ZEND_FUNCTION // zend_API.h #define ZEND_FUNCTION(name) ZEND_NAMED_FUNCTION(ZEND_FN(name)) #define ZEND_NAMED_FUNCTION(name) void name(INTERNAL_FUNCTION_PARAMETERS) #define ZEND_FN(name) zif_##name // zend.h #define INTERNAL_FUNCTION_PARAMETERS zend_execute_data *execute_data, zval *return_value ``` 展開后: ```c void zif_helloworld(zend_execute_data *execute_data, zval *return_value) { zend_string *strg; strg = strpprintf(0, "hello world \n"); RETURN_STR(strg); } ``` 以上擴展可以通過PHP_FUNCTION定義函數,接下來需要注冊函數,每個函數需要實現zend_function_entry結構,然后把zend_function_entry保存到擴展zend_module_entry.functions函數列表即可; zend_function_entry通過PHP_FE()定義,例如: ```c const zend_function_entry hello_functions[] = { PHP_FE(wcl, NULL) PHP_FE(helloworld, NULL) PHP_FE_END /* Must be the last line in hello_functions[] */ }; ``` zend_function_entry結構: ```c 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; ``` PHP_FE展開后: ```c { 'helloworld', zif_helloworld, arg_info, (uint32_t) (sizeof(arg_info)/sizeof(struct _zend_internal_arg_info)-1), flags }, ``` 上面整個結構展開后如下: ```c const zend_function_entry hello_functions[] = { { 'wcl', zif_wcl, arg_info, (uint32_t) (sizeof(arg_info)/sizeof(struct _zend_internal_arg_info)-1), flags }, { 'helloworld', zif_helloworld, arg_info, (uint32_t) (sizeof(arg_info)/sizeof(struct _zend_internal_arg_info)-1), flags }, { NULL, NULL, NULL, 0, 0 } }; ``` 最后將hello_functions賦值給zend_module_entry.functions即可 ### 函數參數解析 通過zend_parse_parameters()解析保存在zend_execute_data的參數; ```c zend_string *str; if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "S", &str) == FAILURE){ ... } ``` - num_args: 通過ZEND_NUM_ARGS()獲得參數個數,TSRMLS_CC用來確保線程安全 - type_spec: 是一個字符串,用來標識解析參數類型 - l 或 L 表示傳入的參數解析為zend_long(l!或L!則會檢測參數是否為null,若為null,則設置為0,同時zend_bool設置為1) - b表示傳入的參數解析為zend_bool - d表示傳入的參數解析為double - s, S, P, p表示傳入的參數解析為string,s解析到char*,且需要一個size_t類型用于獲取字符串長度,S解析到zend_string - a, A, h, H表示傳入的參數解析為array,aA解析到zval,hH解析到hashTable - o, O 對象, 解析到zval - r 資源, 解析到zval - C 類, 解析到zend_class_entry - f 回調函數, 解析到zend_fcall_info - z 任意類型 type_spec標識符: - | 表示之后的參數為可選,例如al|b可以表示3個參數或2個參數,b為可選 - \* 可變參數,可以不傳遞 - \+ 可變參數,至少一個 ### 引用傳參 如果用到參數引用,需要定義參數數組,參數數組定義在ZEND_BEGIN_ARG_INFO_EX和ZEND_END_ARG_INFO兩個宏之間 ```c #define ZEND_BEGIN_ARG_INFO_EX(name, _unused, return_reference, required_num_args) ``` - name參數數組名,對應PHP_FE的第二個參數 - required_num_args 函數有多少個引用參數,就需要在參數數組中定義多少個zend_internal_arg_info zend_internal_arg_info宏定義如下: ```c //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 }, ``` 引用參數通過zend_parse_parameters()解析時只能使用"z"解析,不能再直接解析為zend_value了,否則引用將失效,下面是一個引用參數的例子 ```c // 引用參數數組定義 ZEND_BEGIN_ARG_INFO_EX(arginfo_changeName, 0, 0, 1) ZEND_ARG_INFO(1, name) // zend_internal_arg_info宏定義 ZEND_END_ARG_INFO() PHP_FUNCTION(changeName) { zval *lval; if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &lval) == FAILURE) // z表示任意類型,將參數解析到zval地址 { return; } zval *real_val = Z_REFVAL_P(lval); // Z_REFVAL_P展開后&(lval.value->ref.val) Z_LVAL_P(real_val) = 100; // Z_LVAL_P展開后lval.value->ref.val.value.lval = 100 } const zend_function_entry hello_functions[] = { PHP_FE(changeName, arginfo_changeName) // 第二個參數為參數數組名 PHP_FE_END }; ``` ### 函數返回值 #### 返回數組 ```c PHP_FUNCTION(getArray) { array_init(return_value); add_assoc_string(return_value, "name", "wuzhc"); add_assoc_string(return_value, "address", "GD"); add_next_index_string(return_value, "Guangzhou"); add_next_index_string(return_value, "School"); } ``` - add_assoc_* 添加關聯索引數組元素,如key=>value - add_next_index_* 添加數字索引數組元素 ```php print_r(getArray()); ``` php腳本輸出如下: ```bash Array ( [name] => wuzhc [address] => GD [0] => Guangzhou [1] => School ) ``` ### 調用其他函數 通過call_user_function,內部函數可以調用PHP腳本自定義函數或其他擴展的內部函數 ```c ZEND_API int call_user_function(HashTable *function_table, zval *object, zval *function_name, zval *retval_ptr, uint32_t param_count, zval params[]); ``` - function_table符號表,普通函數邊到EG(function_table),類成員方法保存在zend_class_entry.function - object(成員方法才需要用到,普通函數設置為NULL) - function_name 調用函數名 - retval_ptr 返回值地址 - param_count 參數個數 - params 參數數組 以一個例子為說明: ```php // 調用擴展內部函數my_array_merge,內部函數my_array_merge將調用array_merge函數 $arr1 = array(1,2); $arr2 = array(3,4); $arr3 = my_array_merge($arr1, $arr2); print_r($arr3); ``` my_array_merge實現如下: ```c PHP_FUNCTION(my_array_merge) { zend_array *arr1, *arr2; zval call_func_name, call_func_ret, call_func_params[2]; zend_string *call_func_str; char *func_name = "array_merge"; if (zend_parse_parameters(ZEND_NUM_ARGS(), "hh", &arr1, &arr2) == FAILURE) { return ; } call_func_str = zend_string_init(func_name, strlen(func_name), 0); // 分配zend_string ZVAL_STR(&call_func_name, call_func_str); // call_func_name.value.str = call_func_str(string字符串指針) ZVAL_ARR(&call_func_params[0], arr1); // call_func_params[0].value.arr = arr1 (array數組指針) ZVAL_ARR(&call_func_params[1], arr2); // call_func_params[1].value.arr = arr2 (array數組指針) if (SUCCESS != call_user_function(EG(function_table), NULL, &call_func_name, &call_func_ret, 2, call_func_params)) { zend_string_release(call_func_str); RETURN_FALSE; } else { zend_string_release(call_func_str); RETURN_ARR(Z_ARRVAL(call_func_ret)); // 調用array_merge結果地址會存放在call_func_ret,RETURN_ARR參數是一個數組指針 } } ``` ### 回調函數
                  <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>

                              哎呀哎呀视频在线观看