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

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                經過前面對r2ec以及Bison的介紹,熟悉了PHP語法的實現,我們來動手自己實現一個語法吧。也就是對Zend引擎語法層面的實現。以此來對Zend引擎有更多的了解。 編程語言和社會語言一樣都是會慢慢演進的,不同的語種就像我們的不同國家的語言一樣,他們各有各的特點,語言通常也能反映出一個群體的特質,不同語言的社區氛圍和文化也都會有很大的差異,和現實生活一樣,我們也需要盡可能的去接觸不同的文化,來開闊自己的視野和思維方式,所以我們也建議多學習不同的編程語言。 在這里簡單提一下PHP語言的演進,PHP的語法繼承自Perl的語法,這一點和自然語言也很類似,語言之間會互相影響,比如PHP5開始完善的面向對象機制,已經PHP5.4中增加的命名空間以及閉包等等功能。 PHP是個開源項目,它的發展是由社區來決定的,它也是開放的,如果你有想要改進它的愿望都可以加入到這個社區當中,當然也不是誰都可以改變PHP,重大改進都需要由社區確定,只有有限的人具有對代碼庫的修改權限,如果你發現了PHP的Bug可以去[http://bugs.php.net](http://bugs.php.net)提交Bug,如果同時你也找到了Bug的原因那么你也可以同時附上對Bug的修復補丁,然后在PHP郵件組中進行一些討論,如果沒有問題那么有權限的成員就可以將你的補丁合并進入相應的版本內,更多內容可以參考[附錄D 怎樣為PHP共享自己的力量](#)。 在本小節中將要實現一個對PHP本身語言的一個“需求”:返回變量的名稱。用一小段代碼簡單描述一下這個需求: [php] <?php $demo = 'tipi'; echo var_name($demo); //執行結果,輸出: demo ?> 經過前面的章節,我們了解到,一種PHP語法的內部實現,主要經歷了以下步驟: ![圖7.2 Zend Opcodes執行](http://box.kancloud.cn/2015-07-06_559a632e266db.png) 圖7.2 Zend Opcodes執行 即:詞法分析 => 語法分析 => opcode編譯 => 執行 由此,我們還是要從詞法和語法分析著手。 ### 詞法分析與語法分析[]() 熟悉編譯原理的朋友應該比較熟悉這兩個概念,簡而言之,就是在要運行的程序中,根據原來設定好的“關鍵字”(Tokens),將每條程序指令解釋成為可以由語言解釋器理解的操作。 > 在PHP中,可以使用token_get_all()函數來查看一段PHP代碼生成的Tokens。 PHP的詞法分析和語法分析的實現分別位于Zend目錄下的zend_language_scanner.l和zend_language_parser.y 文件,使用r2ec&flex來編譯。我們要做的,就是在PHP原有的詞法和語法分析中,加入新的Token,在zend_language_scanner.l中加入以下內容: "var_name" { return T_VARIABLE_NAME; } 也就是在此法分析階段遇到var_name這個字符串的時候會被標記為我們定義的T_VARIABLE_NAME token。 同樣,在 zend_language_parser.y 也需要加入對這個token的處理,通常是進行響應的邏輯處理。我們要實現的語法和PHP內置的echo print結構類似,所以我們把這個處理放到 internal_functions_in_yacc規則里面: | T_VARIABLE_NAME '(' T_VARIABLE ')' { zend_do_variable_name(&$$, &$3 TSRMLS_CC); } | T_VARIABLE_NAME T_VARIABLE { zend_do_variable_name(&$$, &$2 TSRMLS_CC); } 上面的兩條規則分別對于類似: <?php echo var_name($varname); echo var_name $varname; 的兩種調用方式,和include() require() 類似。 大家可以很容易理解第一行的定義,如果發現T_VARIABLE_NAME + ( + 變量 + ), 則使用zend_do_variable_name來處理,&$$是當前表達式的返回值, &$3表示第三個表達式的值,也就是T_VARIABLE,也就是一個通常的變量定義。這樣就是把變量相關的信息傳遞進zend_do_variable_name()函數中進行處理。在這里是獲取變量的名稱,然后進行opcode編譯。 ### opcode編譯[]() 在開始之前需要向大家介紹一下PHP opcode的定義及執行。opcode在PHP中通常是一個數字唯一標示,在PHP中目前對每個opcode對應的執行方法的分發提供了3種方式: 首先,我們在Zend/zend_vm_opcodes.h 為我們的新opcode 加入一個宏定義: #define ZEND_VARIABLE_NAME 154 這個數字要求在0-255之間,并且不能與現有opcode重復。 第二步,在Zend/zend_compile.c中加入我們對OPCODE的處理,也就是將代碼操作轉化為op_array放入到opline中: void zend_do_variable_name(znode *result, znode *variable TSRMLS_DC) { // 生成一條zend_op zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); ? // 因為我們需要有返回值, 并且返回值只作為中間值.所以就是一個臨時變量 opline->result.op_type = IS_TMP_VAR; opline->result.u.var = get_temporary_variable(CG(active_op_array)); ? opline->opcode = ZEND_VARIABLE_NAME; opline->op1 = *variable; ? // 我們只需要一個操作數就好了 SET_UNUSED(opline->op2); *result = opline->result; } 這樣,我們就完成了對opcode的編譯。 ### 內部處理邏輯的編寫[]() 經過在上面兩個步驟中,我們已經完成了自定義PHP語法的語法規則定義,opcode編譯。最后的工作,就是定義如何處理自定義的opcode,以及編寫具體的代碼邏輯。在前面關于如何找到opcode具體實現的小節,我們提到 Zend/zend_vm_execute.h中的zend_vm_get_opcode_handler()函數。這個函數就是用來獲取opcode的執行函數。 這個對應的關系,是根據一個公式來進行了,目的是將不同的參數類型分開,對應到多個處理函數,公式是這樣的: return zend_opcode_handlers[opcode * 25 + zend_vm_decode[op->op1.op_type] * 5 + zend_vm_decode[op->op2.op_type]]; 從這個公式我們可以看出,最終的處理函數是與參數類型有關,根據計算,我們要滿足所有類型的映射,盡管我們可以可以使用同一函數進行處理,于是,我們在zend_opcode_handlers這個數組的結尾,加上25個相同的函數定義: void zend_init_opcodes_handlers(void) { static const opcode_handler_t labels[] = { .... ZEND_VARIABLE_NAME_HANDLER, .... ZEND_VARIABLE_NAME_HANDLER } 如果我們不想支持某類型的數據,只需要將類型代入公式計算出的數字做為索引,使opcode_handler_t中相應的項為:ZEND_NULL_HANDLER 最后,我們在Zend/zend_vm_def.h 中增加相應的處理函數。 > 和對語法的修改一樣,opcode處理函數也不是直接修改Zend/zend_vm_execute.h文件的, 這是因為PHP提供了3種opcode分發的機制: 1. CALL 函數調用的方式分發 1. SWITCH 使用SWITCH case 進行分發 1. GOTO 使用goto語句進行分發 之所以提供3中方式主要是從性能出發的,可能在不同的CPU上這幾種調用方式的效率并不一樣。 默認采用的是CALL 回到編寫返回變量名的具體實現,在Zend/zend_vm_def.h中增加如下: static int ZEND_FASTCALL ZEND_VARIABLE_NAME_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); ? // PHP中所有的變量在內部都是存儲在zval結構中的. zval *result = &EX_T(opline->result.u.var).tmp_var; ? // 把變量的名字賦給臨時返回值 Z_STRVAL(*result) = estrndup(opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len); Z_STRLEN(*result) = opline->op1.u.constant.value.str.len; Z_TYPE(EX_T(opline->result.u.var).tmp_var) = IS_STRING; ? ZEND_VM_NEXT_OPCODE(); } 進行完上面的修改之后,我們要刪除r2ec&flex已經編譯好的原文件,即刪除Zend/zend_language*.c文件以使新的語法規則生效。這樣我們再次對PHP源碼進行make時,會自動生成新的編譯好的語法規則處理程序,不過,編譯環境要安裝有lex&yacc和re2c。 從上面的步驟可以看出,php語法的擴展并不困難,而真正的難點在于如何在當前zend內核框架基礎上進行的具體功能的實現,以及到底應該實現什么語法。關于語法的改進通常也是一個漫長的過程,要修改語言的語法通常需要: 1. 提出需求,并說明該語法的作用,以及具體的應用場景,這個語法帶來的好處 1. 大家討論這個需求是否合理,實現啊起來是否有困難,對現有的語法是否造成影響 1. 如果大部分人都認可這個需求最好,那么提出該需求的人可以自己來實現,并讓大家review,如果沒有問題則就可以進入版本庫了。 1. 如果比較有爭議,那可能需要進行投票了。 更多內容請參考附錄:怎么樣為PHP做貢獻小節。
                  <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>

                              哎呀哎呀视频在线观看