站長資訊網(wǎng)
        最全最豐富的資訊網(wǎng)站

        深入淺析PHP中的foreach

        本篇文章帶大家詳解PHP中的foreach。有一定的參考價(jià)值,有需要的朋友可以參考一下,希望對(duì)大家有所幫助。

        深入淺析PHP中的foreach

        語言基礎(chǔ)

        foreach 語法結(jié)構(gòu)提供了遍歷數(shù)組的簡單方式。

        php5之前, foreach僅能用于數(shù)組 php5+, 利用foreach可以遍歷對(duì)象

        foreach僅能夠應(yīng)用于數(shù)據(jù)和對(duì)象,如果嘗試應(yīng)用于其他數(shù)據(jù)類型的變量,或者未初始化的變量將發(fā)出錯(cuò)誤信息。

        有兩種語法:

        /*   遍歷給定的 array_expression 數(shù)據(jù)。每次循環(huán)中, 當(dāng)前單元的值被賦給$value并且數(shù)組內(nèi)部的指針向前移一步(因此下次循環(huán)中將會(huì)得到下一個(gè)單元) */ foreach (array_expression as $value) {     // statement }  foreach (array_expression as $value) :     // statement endforeach;
        /*   同上,只除了當(dāng)前單元格的鍵名也會(huì)在每次循環(huán)中被賦給變量$key */ foreach (array_expression as $key => $value) {     // statement }  foreach (array_expression as $key => $value) :     // statement endforeach;

        還能夠自定義遍歷對(duì)象!

        當(dāng)foreach開始執(zhí)行時(shí), 數(shù)組內(nèi)部的指針會(huì)自動(dòng)指向第一個(gè)單元. 這意味著不需要在foreach循環(huán)之前調(diào)用reset()由于foreach依賴內(nèi)部數(shù)組指針, 在循環(huán)中修改其值將可能導(dǎo)致意外的行為

        可以很容易通過在 $value 之前加上 & 來修改數(shù)組元素. 此方法將以引用 賦值, 而不是拷貝一個(gè)值.

        <?php  $arr = [1, 2, 3, 4]; foreach($arr as &$value) {     $value = $value * 2; }  // $arr is now [2, 4, 6, 8] unset($value); // 最后取消掉引用

        $value的引用僅在被遍歷的數(shù)組可以被引用時(shí)才可用(例如是個(gè)變量)。

        以下代碼無法運(yùn)行:

        <?php /*   此段代碼可以運(yùn)行   運(yùn)行結(jié)果:     1-2     2-4     3-6     4-8 */ foreach (array(1, 2, 3, 4) as &$value) {     echo $value, '-';     $value = $value * 2;     echo $value, PHP_EOL; }

        Warning: 數(shù)組最后一個(gè)元素的 $value 引用在 foreach 循環(huán)之后仍會(huì)保留。建議使用 unset() 來將其銷毀。

        Note: foreach 不支持用 @ 來抑制錯(cuò)誤信息的能力

        foreach 雖然簡單, 不過它可能出現(xiàn)一些意外行為, 特別是代碼涉及到引用的時(shí)候。

        問題研究

        問題一: 如下代碼運(yùn)行結(jié)果為何不是 2/4/6 ?

        <?php $arr = [1, 2, 3];  foreach ($arr as $k => &$v) {     $v = $v * 2; }  foreach ($arr as $k => $v) {     echo $v, PHP_EOL; }  /* 輸出:     2     4     4 */

        我們可以認(rèn)為 foreach($arr as &$v) 結(jié)構(gòu)隱含了如下操作, 分別將數(shù)組當(dāng)前的 賦值給 $k$v. 具體展開形如:

        <?php foreach ($arr as $k => $v) {     $k = currentKey();     $v = currentVal();     // 繼續(xù)運(yùn)行用戶代碼 }

        根據(jù)上述理論, 現(xiàn)在我們重新來分析下第一個(gè)foreach:

        循環(huán) 備注 $arr值
        循環(huán) 1-1 由于$v是一個(gè)引用, 因此 $v = &$arr[0], $v = $v * 2 相當(dāng)于 $arr[0] * 2 [2, 2, 3]
        循環(huán) 1-2 $v = &$arr[1] [2, 4, 3]
        循環(huán) 1-3 $v = &$arr[2] [2, 4, 6]
        循環(huán) 2-1 隱含操作 $v = $arr[0] 被觸發(fā), 由于此時(shí) $v 仍是 $arr[2] 的引用, 相當(dāng)于 $arr[2] = $arr[0] [2, 4, 2]
        循環(huán) 2-2 $v = $arr[1], 即$arr[2] = $arr[1] [2, 4, 4]
        循環(huán) 2-3 $v = $arr[2], 即$arr[2] = $arr[2] [2, 4, 4]

        如何解決此類問題呢? PHP手冊(cè)上有一段提醒:

        Warning: 數(shù)組最后一個(gè)元素的 $value 引用在 foreach 循環(huán)之后仍會(huì)保留。建議使用 unset() 來將其銷毀。

        <?php $arr = [1, 2, 3];  foreach ($arr as $k => &$v) {     $v = $v * 2; } unset($v); foreach ($arr as $k => $v) {     echo $v, PHP_EOL; }  /* 輸出:     2     4     6 */

        從這個(gè)問題可以看出, 引用很可能會(huì)伴隨副作用。如果不希望無意識(shí)的修改導(dǎo)致數(shù)據(jù)內(nèi)容變更, 最好及時(shí)unset掉這些引用。

        問題二: 如下代碼運(yùn)行結(jié)果為何不是 0=>a 1=>b 2=>c

        <?php $arr = ['a', 'b', 'c'];  foreach ($arr as $k => $v) {     echo key($arr), "=>", current($arr), PHP_EOL; }  foreach ($arr as $k => &$v) {     echo key($arr), "=>", current($arr), PHP_EOL; } /* #php5.6 1=>b 1=>b 1=>b 1=>b 2=>c =>  #php7 0=>a 0=>a 0=>a 0=>a 0=>a 0=>a */

        按照手冊(cè)中的說法, key和current分別是獲取數(shù)據(jù)中當(dāng)前元素的鍵值。 那為何 key($arr) 一直是0,current($arr) 一直是'a'呢?

        先用vld查看編譯后的 opcode:

        ?  demo /usr/local/Cellar/php/7.2.7/bin/php -dvld.active=1 a.php Finding entry points Branch analysis from position: 0 Jump found. (Code = 77) Position 1 = 2, Position 2 = 15 Branch analysis from position: 2 Jump found. (Code = 78) Position 1 = 3, Position 2 = 15 Branch analysis from position: 3 Jump found. (Code = 42) Position 1 = 2 Branch analysis from position: 2 Branch analysis from position: 15 Jump found. (Code = 62) Position 1 = -2 Branch analysis from position: 15 filename:       /Users/jianyong/demo/a.php function name:  (null) number of ops:  17 compiled vars:  !0 = $arr, !1 = $v, !2 = $k line     #* E I O op                           fetch          ext  return  operands -------------------------------------------------------------------------------------    2     0  E >   ASSIGN                                                   !0, <array>    4     1      > FE_RESET_R                                       $4      !0, ->15          2    > > FE_FETCH_R                                       ~5      $4, !1, ->15          3    >   ASSIGN                                                   !2, ~5    5     4        INIT_FCALL                                               'key'          5        SEND_VAR                                                 !0          6        DO_ICALL                                         $7          7        ECHO                                                     $7          8        ECHO                                                     '%3D%3E'          9        INIT_FCALL                                               'current'         10        SEND_VAR                                                 !0         11        DO_ICALL                                         $8         12        ECHO                                                     $8         13        ECHO                                                     '%0A'         14      > JMP                                                      ->2         15    >   FE_FREE                                                  $4    7    16      > RETURN                                                   1  branch: #  0; line:     2-    4; sop:     0; eop:     1; out1:   2; out2:  15 branch: #  2; line:     4-    4; sop:     2; eop:     2; out1:   3; out2:  15 branch: #  3; line:     4-    5; sop:     3; eop:    14; out1:   2 branch: # 15; line:     5-    7; sop:    15; eop:    16; out1:  -2 path #1: 0, 2, 3, 2, 15, path #2: 0, 2, 15, path #3: 0, 15, 0=>a 0=>a 0=>a

        PHP7新特性之foreach

        • [x] foreach 循環(huán)對(duì)數(shù)組內(nèi)部指針不再起作用, 在PHP7之前, 當(dāng)數(shù)據(jù)通過foreach迭代時(shí), 數(shù)組指針會(huì)移動(dòng)。
        <?php $array = [0, 1, 2]; foreach ($array as &$val) {     var_dump(current($array)); }
        版本 結(jié)果 說明
        PHP5 int(1) int(2) bool(false) 數(shù)組指針會(huì)移動(dòng)
        PHP7 int(0) int(0) int(0) 數(shù)據(jù)指針不再移動(dòng)
        • [x] 按照值進(jìn)行循環(huán)時(shí), 對(duì)數(shù)組的修改是不會(huì)影響循環(huán)。

        foreach按照值進(jìn)行循環(huán)的時(shí)候(by-value), foreach是對(duì)該數(shù)組的一個(gè)拷貝進(jìn)行操作. 所以在循環(huán)過程中修改不影響循環(huán)結(jié)果

        <?php $arr = [0, 1, 2]; $ref = &$arr;  foreach ($arr as $val) {     var_dump($val);     unset($arr[1]); }
        版本 結(jié)果 說明
        PHP5 int(0) int(2) 會(huì)將unset的數(shù)據(jù)跳過
        PHP7 int(0) int(1) int(2) 對(duì)數(shù)組的改動(dòng)不影響循環(huán)
        • [x] 按照引用進(jìn)行循環(huán)的時(shí)候, 對(duì)數(shù)組的修改會(huì)影響循環(huán)
        <?php $arr = [0, 1, 2]; $ref = &$arr;  foreach ($arr as &$val) {     var_dump($val);     unset($arr[1]); }
        版本 結(jié)果
        PHP5 int(0) int(2)
        PHP7 int(0) int(2)
        • [x] 對(duì)簡單對(duì)象plain(non-Traversable)的循環(huán)

        在簡單對(duì)象的循環(huán), 不管是按照值循環(huán)還是引用循環(huán), 和按照引用對(duì)數(shù)組循環(huán)的行為是一樣的, 不過對(duì)位置的管理會(huì)更加精確

        • [x] 對(duì)迭代對(duì)象(Traversable objects)對(duì)象行為和之前一致

        stackoverflow 上面的解釋, Traversable objects is one that implements Iterator or IteratorAggregate interface

        如果一個(gè)對(duì)象實(shí)現(xiàn)了 Iterator 或者 IteratorAggregate 接口, 即可稱之為迭代對(duì)象

        推薦學(xué)習(xí):《PHP視頻教程》

        贊(0)
        分享到: 更多 (0)
        網(wǎng)站地圖   滬ICP備18035694號(hào)-2    滬公網(wǎng)安備31011702889846號(hào)
        主站蜘蛛池模板: 亚洲精品视频免费观看| 国内少妇偷人精品视频免费 | 精品视频无码一区二区三区| 国产精品主播一区二区| 精品视频第一页| 亚洲AV成人精品网站在线播放 | 亚洲色精品vr一区二区三区| 国产精品片在线观看手机版| 成人午夜精品网站在线观看| 亚洲∧v久久久无码精品| 人妻少妇看A偷人无码精品视频| 中文字幕一区二区精品区| 国产日韩精品欧美一区| 亚洲精品午夜无码电影网| 日本五区在线不卡精品| 久久国产精品免费一区| 国产精品白丝jkav网站| 亚洲国产综合91精品麻豆| 国产欧美国产精品第一区| 99久久久国产精品免费无卡顿| 麻豆aⅴ精品无码一区二区| 亚洲精品自产拍在线观看| 久99精品视频在线观看婷亚洲片国产一区一级在线 | 精品亚洲永久免费精品| 99久久久精品免费观看国产| 精品国精品无码自拍自在线| 久久精品中文无码资源站| 久久久久人妻精品一区| 日韩精品内射视频免费观看| 亚洲中文精品久久久久久不卡| 亚洲欧美精品SUV| 无码国产乱人伦偷精品视频| 青草国产精品久久久久久| 久久精品蜜芽亚洲国产AV| 国语精品一区二区三区| 国产精品久久久久久| 九九热在线视频观看这里只有精品 | 国产精品国产精品国产专区不卡| 99精品久久久久中文字幕| 国产精品影音先锋| 在线人成精品免费视频|