<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國際加速解決方案。 廣告
                # ZEND引擎編譯過程 ZE是一個CISC(復雜指令處理器),正是由于它的存在,所以才能使得我們寫PHP腳本時不需要考慮所在的操作系統類型是什么, 它支持170多條指令(定義在 Zend/zend_vm_opcodes.h),包括從最簡單的ZEND_ECHO(echo)到復雜的 ZEND_INCLUDE_OR_EVAL(include,require),所有我們編寫的PHP都會最終被處理為這些指令(op code)的序列,從而最終被執行. #### 從最初我們編寫的PHP腳本->到最后腳本被執行->得到執行結果,這個過程,可以分為如下幾個階段 * 首先,Zend Engine(ZE),調用詞法分析器,將我們要執行的PHP源文件,去掉空格 ,注釋,分割成一個一個的token. * 然后,ZE會將得到的token forward給語法分析器,生成抽象語法樹. * 然后,ZE調用zend_compile_top_stmt()函數將抽象語法樹解析為一個一個的op code,opcode一般會以op array的形式存在,它是PHP執行的中間語言. * 最后,ZE調用zend_executor來執行op array,輸出結果. ![ZEND引擎編譯執行過程](https://box.kancloud.cn/fb2f3081a86006682ce5a4f54351184c_1031x701.png) #### PHP編譯PHP代碼時用到的工具 re2c: 詞法分析器,將輸入分割為一個個有意義的詞塊,稱為token,Zend/zend_language_scanner.l 文件是re2c的規則文件. bison: 語法分析器,確定詞法分析器分割出的token是如何彼此關聯的,Zend/zend_language_parser.y 文件是bison的規則文件. # CG變量 zend_global.h/_zend_compiler_globals # Token ```php <?php $token = token_get_all('<?php $str="hello world";echo $str;'); foreach ($token as $key => &$value) { if(is_array($value)&&(!empty($value[0]))){ $value[0] = token_name(intval($value[0])); } } print_r($token); ``` **輸出:** ``` Array ( [0] => Array ( [0] => T_OPEN_TAG //TOKEN名稱 [1] => <?php //匹配到的字符 [2] => 1 //行號 ) [1] => Array ( [0] => T_VARIABLE [1] => $str [2] => 1 ) [2] => = [3] => Array ( [0] => T_CONSTANT_ENCAPSED_STRING [1] => "hello world" [2] => 1 ) [4] => ; [5] => Array ( [0] => T_ECHO [1] => echo [2] => 1 ) [6] => Array ( [0] => T_WHITESPACE [1] => [2] => 1 ) [7] => Array ( [0] => T_VARIABLE [1] => $str [2] => 1 ) [8] => ; ) ``` # AST: #### PHP7之后的編譯過程加了一層抽象語法樹,使編譯過程更清晰規范,易于優化,語法規則減少,編譯速度變快,編譯占用內存增加. #### 查看AST的工具: * https://github.com/nikic/PHP-Parser (PHP解析工具) * https://pecl.php.net/package/ast (擴展) * https://dooakitestapp.herokuapp.com/phpast/webapp/ (在線) ![](https://box.kancloud.cn/80202a7ffea6328f2ce54d704c1b9338_561x515.png) #### 相關數據結構:Zend/zend_ast.h ```c enum _zend_ast_kind { /* 特殊節點 special nodes */ ZEND_AST_ZVAL = 1 << ZEND_AST_SPECIAL_SHIFT, ZEND_AST_ZNODE, /* 聲明節點 declaration nodes */ ZEND_AST_FUNC_DECL, ZEND_AST_CLOSURE, ZEND_AST_METHOD, ZEND_AST_CLASS, /* 列表節點 list nodes */ ZEND_AST_ARG_LIST = 1 << ZEND_AST_IS_LIST_SHIFT, ZEND_AST_ARRAY, ... ZEND_AST_USE, /* 普通節點 0 child nodes */ ZEND_AST_MAGIC_CONST = 0 << ZEND_AST_NUM_CHILDREN_SHIFT, ZEND_AST_TYPE, /* 1 child node */ ZEND_AST_VAR = 1 << ZEND_AST_NUM_CHILDREN_SHIFT, ZEND_AST_CONST, ... /* 4 child nodes */ ZEND_AST_FOR = 4 << ZEND_AST_NUM_CHILDREN_SHIFT, ZEND_AST_FOREACH, }; struct _zend_ast { zend_ast_kind kind; /* 節點類型 Type of the node (ZEND_AST_* enum constant) */ zend_ast_attr attr; /* 附加信息 Additional attribute, use depending on node type */ uint32_t lineno; /* 行號 Line number */ zend_ast *child[1]; /* 子節點 Array of children (using struct hack) */ }; /* Same as zend_ast, but with children count, which is updated dynamically */ typedef struct _zend_ast_list { zend_ast_kind kind; zend_ast_attr attr; uint32_t lineno; uint32_t children; zend_ast *child[1]; } zend_ast_list; /* Lineno is stored in val.u2.lineno */ //php腳本中的變量,文字,變量名,調用函數名等,總是終端葉節點 typedef struct _zend_ast_zval { zend_ast_kind kind; zend_ast_attr attr; zval val; } zend_ast_zval; /* Separate structure for function and class declaration, as they need extra information. */ /*聲明類型的始終有四個子節點 AST_FUNC_DECL函數定義 1:AST_PARAM_LIST(參數),2:未使用, 3:AST_STMT_LIST(函數內部),4:AST_ZVAL(返回值類型) AST_CLOSURE匿名函數定義 1:AST_PARAM_LIST(參數),2:AST_CLOSURE_USES(use),3:AST_STMT_LIST(函數內部),4:AST_ZVAL(返回值類型) AST_METHOD方法定義 1:AST_PARAM_LIST(參數),2:未使用,3:AST_STMT_LIST(函數內部),4:AST_ZVAL(返回值類型) AST_CLASS類,匿名類,trait,接口定義 1:AST_ZVAL(繼承源),2:AST_NAME_LIST(implements),3:AST_STMT_LIST(內部定義),4:未使用 */ typedef struct _zend_ast_decl { zend_ast_kind kind; zend_ast_attr attr; /* Unused - for structure compatibility */ uint32_t start_lineno; uint32_t end_lineno; uint32_t flags; unsigned char *lex_pos; zend_string *doc_comment; zend_string *name; zend_ast *child[4]; } zend_ast_decl; ``` # OPCEODE: opcode是將PHP代碼編譯產生的Zend虛擬機可識別的指令,php7共有173個opcode,定義在zend_vm_opcodes.h中,這些中間代碼會被Zend VM(Zend虛擬機)直接執行. #### opcode查看: * https://3v4l.org/UBstu/vld#output (在線) * https://pecl.php.net/package/vld (擴展) #### VLD輸出: Finding entry points Branch analysis from position: 0 Jump found. (Code = 62) Position 1 = -2 filename: /in/MSj65 function name: (null) number of ops: 3 compiled vars: !0 = $str line #* E I O op fetch ext return operands ------------------------------------------------------------------------------------- 4 0 E > ASSIGN !0, 'hello+world' 6 1 ECHO !0 2 > RETURN 1 ![](https://box.kancloud.cn/f15e7f8607d592204b9ddb3137e596cf_1920x1080.png) #### 相關數據結構Zend/compile.h 參考:http://blog.csdn.net/phpkernel/article/details/5721384 http://www.bo56.com/php7%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90%E4%B9%8Bcg%E5%92%8Ceg/ ```c struct _zend_op_array { //common是普通函數或類成員方法對應的opcodes快速訪問時使用的字段,后面分析PHP函數實現的時候會詳細講 ... 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]; }; struct _zend_op { const void *handler; //對應執行的C語言function,即每條opcode都有一個C function處理 znode_op op1; //操作數1 znode_op op2; //操作數2 znode_op result; //返回值 uint32_t extended_value; //用來區別被重載的操作符 uint32_t lineno; zend_uchar opcode; //opcode指令 zend_uchar op1_type; //操作數1類型,為IS_CONST, IS_TMP_VAR, IS_VAR, IS_UNUSED, or IS_CV zend_uchar op2_type; //操作數2類型 zend_uchar result_type; //返回值類型 }; //操作數結構 typedef union _znode_op { uint32_t constant; uint32_t var; uint32_t num; uint32_t opline_num; /* Needs to be signed */ uint32_t jmp_offset; } znode_op; ``` #### 操作數類型: ```c // Zend/zend_compile.h #define IS_CONST (1<<0) //1 #define IS_TMP_VAR (1<<1) //2 #define IS_VAR (1<<2) //4 #define IS_UNUSED (1<<3) //8 #define IS_CV (1<<4) //16 ``` * IS_CONST:字面量,編譯時就可確定且不會改變的值,比如:$a = "hello~",其中字符串"hello~"就是常量 * IS_TMP_VAR:臨時變量,比如:$a = "hello~" . time(),其中"hello~" . time()的值類型就是IS_TMP_VAR,再比如:$a = "123" + $b,"123" + $b的結果類型也是IS_TMP_VAR,從這兩個例子可以猜測,臨時變量多是執行期間其它類型組合現生成的一個中間值,由于它是現生成的,所以把IS_TMP_VAR賦值給IS_CV變量時不會增加其引用計數 * IS_VAR:PHP變量,這個很容易認為是PHP腳本里的變量,其實不是,這里PHP變量的含義可以這樣理解:PHP變量是沒有顯式的在PHP腳本中定義的,不是直接在代碼通過$var_name定義的.這個類型最常見的例子是PHP函數的返回值,再如$a[0]數組這種,它取出的值也是IS_VAR,再比如$$a這種 * IS_UNUSED:表示操作數沒有用 * IS_CV:PHP腳本變量,即腳本里通過$var_name定義的變量,這些變量是編譯階段確定的,所以是compile variable, #### opcode handler 的索引算法 //zend_vm_execute.h -> /zend_vm_get_opcode_handler() #### 編譯后的CG(active_op_array)結構圖 ### 參考資料: PHP代碼的編譯:https://github.com/pangudashu/php7-internal PHP官網關于AST的RFC: https://wiki.php.net/rfc/ast_based_parsing_compilation_process https://wiki.php.net/rfc/abstract_syntax_tree AST徹底解說:https://www.slideshare.net/do_aki/php-ast VLD擴展使用指南:http://www.php-internals.com/book/?p=C-php-vld
                  <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>

                              哎呀哎呀视频在线观看