<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 功能強大 支持多語言、二開方便! 廣告
                foreach是PHP的關鍵字,用來實現基于數據的循環。基于數據循環語句的循環是由數據結構中的元素的數目來控制的。一般來說,基于數據的循環語句會使用一種稱之為迭代器的函數來實現元素的遍歷。 除了foreach,PHP還提供了預定義的一些函數來實現對數組的迭代訪問操作,如current, next, reset等等。然而我們使用得最多的還是foreach語句,foreach可以直接迭代訪問數組,如果用戶自己定義的對象需要使用此語句進行迭代訪問,必須實現SPL的迭代器。 這一小節,我們具體介紹PHP中foreach的實現過程。foreach 語法結構提供了遍歷數組的簡單方式。foreach 僅能夠應用于數組和對象,如果嘗試應用于其他數據類型的變量,或者未初始化的變量,將導致錯誤。foreach每次循環時,當前單元的值被賦給 $value 并且數組內部的指針向前移一步(因此下一次循環中將會得到下一個單元)。 ### 循環過程的實現[]() foreach語句在語法解析時對應三個操作: 1. zend_do_foreach_begin: 循環開始操作,生成FE_RESET中間代碼,數組會在循環開始時執行RESET操作,即我們使用foreach遍歷時不用每次重新手動RESET,同時此操作也會生成獲取變量的FE_FETCH中間代碼。 1. zend_do_foreach_cont:根據需要獲取變量的狀態判斷是否引用,此處的引用會影響FE_RESET的初始化操作和FE_FETCH中間代碼的獲取變量操作。 1. zend_do_foreach_end:設置ZEND_JMP中間代碼,設置下一條OP,以跳出循環,結束循環,清理工作。 這三個操作都是語法解析時對應的函數名,在編譯過程中會直接調用。他們形成的中間代碼在PHP內核執行時,形成的循環遍歷效果是:在foreach遍歷之前, PHP內核首先會有個FE_RESET操作來重置數組的內部指針,也就是pInternalPointer, 然后通過每次FE_FETCH將pInternalPointer指向數組的下一個元素,從而實現順序遍歷。并且每次FE_FETCH的結果都會被一個全局的中間變量存儲,以給下一次的獲取元素使用。 如下面這段代碼: $arr = [array](http://www.php.net/array)(1, 2, 3, 4, 5); ? foreach ($arr as $key => $row) { [echo](http://www.php.net/echo) $key , $row; } 這是一個標準的foreach循環使用示例。在VLD擴展中我們可以看到如下的中間代碼: number of ops: 16 compiled vars: !0 = $arr, !1 = $key, !2 = $row line # * op fetch ext return operands --------------------------------------------------------------------------------- 2 0 > INIT_ARRAY ~0 1 1 ADD_ARRAY_ELEMENT ~0 2 2 ADD_ARRAY_ELEMENT ~0 3 3 ADD_ARRAY_ELEMENT ~0 4 4 ADD_ARRAY_ELEMENT ~0 5 5 ASSIGN !0, ~0 4 6 > FE_RESET $2 !0, ->14 7 > > FE_FETCH $3 $2, ->14 8 > ZEND_OP_DATA ~5 9 ASSIGN !2, $3 10 ASSIGN !1, ~5 5 11 ECHO !1 12 ECHO !2 6 13 > JMP ->7 14 > SWITCH_FREE $2 7 15 > RETURN 1 當我們通過RESET初始化數組后,FETCH會獲取變量,并將數組的內部指針指向一個元素。在前面我們講過,常規情況下OPCODE的執行是一條一條依次執行的,則在FE_FETCH獲取完變量后,PHP內核會依次執行后續的OPCODE,當執行到JMP時,會重新跳到->7,即再一次獲取變量,如此構成一個循環。當FE_FETCH執行失敗時,會跳轉到->14,即SWITCH_FREE,從而結束整個循環。 ### 指針的意外行為[]() 在PHP手冊中有這樣一個NOTE: > Note: 當 foreach 開始執行時,數組內部的指針會自動指向第一個單元。這意味著不需要在 foreach 循環之前調用 reset()。 由于 foreach 依賴內部數組指針,在循環中修改其值將可能導致意外的行為。 比如這樣一段代碼: $arr = array(1,2,3,4,5); ? foreach($arr as $key => $row) { echo key($arr), '=>', current($arr), "\r\n"; } 如果在$row加上引用呢?如果在遍歷前添加 **$g = $arr;** 呢?結果是上面示例的代碼只會輸出數組的第二個元素。修改建議的代碼會依次輸出變量,但是第一個元素并沒有在輸出結果中出現。 這個異常引申出三個問題: 1. 為什么foreach循環體中執行key或current會顯示第二個元素(非引用情況)?以key函數為例,我們執行函數調用時,會執行中間代碼SEND_REF,此中間代碼會將沒有設置引用的變量復制一份并設置為引用。當進入循環體時,PHP內核已經經過了一次fetch操作,相當于執行了一次next操作,當前元素指向第二個元素。因此我們在foreach的循環體中執行key函數時,key中調用的數組變量為PHP執行了一次fetch操作的數組拷貝,此時foreach的內部指針指向第二個元素。 1. 為什么在foreach中執行end等操作,其循環過程不變?在遍歷的代碼中通過end,next等操作數組的指針,數組的指針不會變化,這是因為在PHP內核進行FETCH操作時,會通過中間變量存儲當前操作數組的內部指針,每遍歷一個元素,會先獲取之前存儲的指針位置,獲取下一個元素后,再恢復指針位置,關鍵在于FETCH OPCODE執行過程中的中間變量。 1. 為什么$row的引用和非引用情況下輸出結果不同?如果是引用,PHP內核在reset數組時,會直接分裂數組,生成一個數組的拷貝,并將其設置為引用。如果是非引用,PHP內核在reset數組時,當數組的引用計數大于1,并且不存在引用時,會拷貝數組供foreach使用,其它情況使用原數組,將其引用計數加1。因為引用的不同,在循環體中給函數傳遞參數時其結果不同,導致看到的foreach數組內部指針變化的不同。對于非引用且引用計數大于1的情況,其本身就是兩個不同的數組,在RESET時就不同了。
                  <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>

                              哎呀哎呀视频在线观看