<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中,函數分為倆種: 一種是zend_internal_function, 這種函數是由擴展或者Zend/PHP內核提供的,用’C/C++’編寫的,可以直接執行的函數. 另外一種是zend_user_function, 這種函數呢,就是我們經常在見的,用戶在PHP腳本中定義的函數,這種函數最終會被ZE翻譯成opcode array來執行 zval : zend_function func 類型成員 EG(function_table)是一個哈希表,記錄的就是PHP中所有的函數. zend_internal_function,zend_function,zend_op_array這三種結構在一定程序上存在公共的元素, 于是這些元素以聯合體的形式共享內存,并且在執行過程中對于一個函數,這三種結構對應的字段在值上都是一樣的, 于是可以在一些結構間發生完美的強制類型轉換.zend_op_array與zend_internal_function結構的起始位置都有common中的幾個成員,common可以看作是op_array、internal_function的header,不管是什么哪種函數都可以通過zend_function.common.xx快速訪問,zend_function可以與zend_op_array互換,zend_function可以與zend_internal_function互換,但是一個zend_op_array結構轉換成zend_function是不能再次轉變成zend_internal_function結構的,反之亦然. ### 結構 ```c //zend_compile.h union _zend_function { zend_uchar type; /* 函數類型 */ uint32_t quick_arg_flags; struct { zend_uchar type; /* never used */ zend_uchar arg_flags[3]; /* bitset of arg_info.pass_by_reference */ uint32_t fn_flags; //作為方法時的訪問類型等,如ZEND_ACC_STATIC等 zend_string *function_name; //函數名稱 zend_class_entry *scope; //成員方法所屬類,面向對象實現中用到 union _zend_function *prototype;//函數原型 uint32_t num_args; //參數數量 uint32_t required_num_args; //必傳參數數量 zend_arg_info *arg_info; //參數信息 } common; zend_op_array op_array; //函數實際編譯為普通的zend_op_array zend_internal_function internal_function; }; //內部函數結構 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; //用戶自定義函數結構 struct _zend_op_array { /* Common elements common是普通函數或類成員方法對應的opcodes快速訪問時使用的字段*/ 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_arg_info *arg_info; /* END of common elements */ uint32_t *refcount; uint32_t last; zend_op *opcodes; //opcode指令數組 int last_var; //PHP代碼里定義的變量數:op_type為IS_CV的變量,不含IS_TMP_VAR、IS_VAR的,編譯前0,然后發現一個新變量這個值就加1 uint32_t T; //臨時變量數:op_type為IS_TMP_VAR、IS_VAR的變量 zend_string **vars; //這個數組在ast編譯期間配合last_var用來確定各個變量的編號,非常重要的一步操作//PHP變量名數組 ... HashTable *static_variables; //靜態變量符號表:通過static聲明的 ... int last_literal; //字面量數量 zval *literals; //字面量(常量)數組,這些都是在PHP代碼定義的一些值 int cache_size; //運行時緩存數組大小 void **run_time_cache; //運行時緩存,主要用于緩存一些znode_op以便于快速獲取數據,后面單獨介紹這個機制 void *reserved[ZEND_MAX_RESERVED_RESOURCES]; }; //函數類型 #define ZEND_INTERNAL_FUNCTION 1 //內置的函數 #define ZEND_USER_FUNCTION 2 //用戶函數 #define ZEND_OVERLOADED_FUNCTION 3 //對象中__call相關 #define ZEND_EVAL_CODE 4 //eval code #define ZEND_OVERLOADED_FUNCTION_TEMPORARY 5 //對象中__call相關 ``` ## 用戶自定義函數 PHP在編譯階段將用戶自定義的函數編譯為獨立的opcodes,保存在EG(function_table)中,調用時重新分配新的zend_execute_data(相當于運行棧),然后執行函數的opcodes,調用完再還原到舊的zend_execute_data,繼續執行,關于zend引擎execute階段后面會詳細分析. zend_function的結構中的op_array存儲了該函數中所有的操作,當函數被調用時,ZE就會將這個op_array中的opline一條條順次執行, 并將最后的返回值返回. 從VLD擴展中查看的關于函數的信息可以看出,函數的定義和執行是分開的,一個函數可以作為一個獨立的運行單元而存在. ### 函數參數 參數名稱也在zend_op_array.vars中,編號首先是從參數開始的,所以按照參數順序其編號依次為0、1、2... 參數的其它信息通過zend_arg_info結構記錄: ```c typedef struct _zend_arg_info { zend_string *name; //參數名 zend_string *class_name;//類名 zend_uchar type_hint; //顯式聲明的參數類型,比如(array $param_1) zend_uchar pass_by_reference; //是否引用傳參,參數前加&的這個值就是1 zend_bool allow_null; //是否允許為NULL,注意:這個值并不是用來表示參數是否為必傳的 zend_bool is_variadic; //是否為可變參數,即...用法,與golang的用法相同,5.6以上新增的一個用法:function my_func($a, ...$b){...} } zend_arg_info; ``` 每個參數都有一個上面的結構,所有參數的結構保存在zend_op_array.arg_info數組中,這里有一個地方需要注意:zend_op_array->arg_info數組保存的并不全是輸入參數,如果函數聲明了返回值類型則也會為它創建一個zend_arg_info,這個結構在arg_info數組的第一個位置,這種情況下zend_op_array->arg_info指向的實際是數組的第二個位置,返回值的結構通過zend_op_array->arg_info[-1]讀取. ### 編譯過程 zend引擎編譯課程再講解 ## 內部函數 內部函數的定義非常簡單,我們只需要創建一個普通的C函數,然后創建一個zend_internal_function結構添加到 EG(function_table) ### 解析函數參數 ZEND_API int zend_parse_parameters(int num_args TSRMLS_DC, char *type_spec, ...) 第一個參數num_args表明表示想要接收的參數個數,我們經常使用ZEND_NUM_ARGS() 來表示對傳入的參數“有多少要多少”. 第二參數應該總是宏 TSRMLS_CC . 第三個參數 type_spec 是一個字符串,用來指定我們所期待接收的各個參數的類型,有點類似于 printf 中指定輸出格式的那個格式化字符串. 剩下的參數就是我們用來接收PHP參數值的變量的指針. ### PHP自帶函數講解 ```c // ext/standard/string.c : line 2744 static void php_ucfirst(char *str) { register char *r; r = str; *r = toupper((unsigned char) *r); } PHP_FUNCTION(ucfirst) { zend_string *str; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STR(str) ZEND_PARSE_PARAMETERS_END(); if (!ZSTR_LEN(str)) { RETURN_EMPTY_STRING(); } ZVAL_STRINGL(return_value, ZSTR_VAL(str), ZSTR_LEN(str)); php_ucfirst(Z_STRVAL_P(return_value)); } // ext/standard/php_string.h PHP_FUNCTION(ucfirst); ``` ### 注冊新函數 在擴展課程再講解 ### 函數注冊過程 ## 測試 ```php <?php /* //列出所有函數 function test(){ print_r(get_defined_functions()); } test(); */ /* 調用用戶定義函數 function test(){} test(); */ /* 調用內部函數 */ strtoupper('test'); ``` # 函數 ## 分類 ## zval function ## 結構 # 內部函數 ## 擴展結構 # opcode # 編譯過程示例 ## 參考資料: http://www.laruence.com/ https://github.com/pangudashu/php7-internal/ http://www.php-internals.com/book
                  <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>

                              哎呀哎呀视频在线观看