摘要:建議使用來將其銷毀。那為何一直是,一直是呢先用查看編譯后的新特性之循環(huán)對數(shù)組內(nèi)部指針不再起作用在之前當(dāng)數(shù)據(jù)通過迭代時數(shù)組指針會移動。版本結(jié)果說明數(shù)組指針會移動數(shù)據(jù)指針不再移動按照值進(jìn)行循環(huán)時對數(shù)組的修改是不會影響循環(huán)。
招聘
標(biāo)簽(空格分隔): 招聘 PHP 國貿(mào)
foreach 語法結(jié)構(gòu)提供了遍歷數(shù)組的簡單方式。
php5之前, foreach僅能用于數(shù)組
php5+, 利用foreach可以遍歷對象
foreach僅能夠應(yīng)用于數(shù)據(jù)和對象,如果嘗試應(yīng)用于其他數(shù)據(jù)類型的變量,或者未初始化的變量將發(fā)出錯誤信息。
有兩種語法:
/* 遍歷給定的 array_expression 數(shù)據(jù)。每次循環(huán)中, 當(dāng)前單元的值被賦給$value并且數(shù)組內(nèi)部的指針向前移一步(因此下次循環(huán)中將會得到下一個單元) */ foreach (array_expression as $value) { // statement } foreach (array_expression as $value) : // statement endforeach;
/* 同上,只除了當(dāng)前單元格的鍵名也會在每次循環(huán)中被賦給變量$key */ foreach (array_expression as $key => $value) { // statement } foreach (array_expression as $key => $value) : // statement endforeach;
還能夠自定義遍歷對象!
當(dāng)foreach開始執(zhí)行時, 數(shù)組內(nèi)部的指針會自動指向第一個單元. 這意味著不需要在foreach循環(huán)之前調(diào)用reset()
由于foreach依賴內(nèi)部數(shù)組指針, 在循環(huán)中修改其值將可能導(dǎo)致意外的行為
可以很容易通過在 $value 之前加上 & 來修改數(shù)組元素. 此方法將以引用 賦值, 而不是拷貝一個值.
$value的引用僅在被遍歷的數(shù)組可以被引用時才可用(例如是個變量)。
以下代碼無法運(yùn)行:
Warning: 數(shù)組最后一個元素的 $value 引用在 foreach 循環(huán)之后仍會保留。建議使用 unset() 來將其銷毀。Note: foreach 不支持用 @ 來抑制錯誤信息的能力
foreach 雖然簡單, 不過它可能出現(xiàn)一些意外行為, 特別是代碼涉及到引用的時候。
問題研究 問題一: 如下代碼運(yùn)行結(jié)果為何不是 2/4/6 ?&$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. 具體展開形如:
$v) { $k = currentKey(); $v = currentVal(); // 繼續(xù)運(yùn)行用戶代碼 }根據(jù)上述理論, 現(xiàn)在我們重新來分析下第一個foreach:
循環(huán) | 備注 | $arr值 |
---|---|---|
循環(huán) 1-1 | 由于$v是一個引用, 因此 $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ā), 由于此時 $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手冊上有一段提醒:
Warning: 數(shù)組最后一個元素的 $value 引用在 foreach 循環(huán)之后仍會保留。建議使用 unset() 來將其銷毀。
&$v) { $v = $v * 2; } unset($v); foreach ($arr as $k => $v) { echo $v, PHP_EOL; } /* 輸出: 2 4 6 */
從這個問題可以看出, 引用很可能會伴隨副作用。如果不希望無意識的修改導(dǎo)致數(shù)據(jù)內(nèi)容變更, 最好及時unset掉這些引用。
問題二: 如下代碼運(yùn)行結(jié)果為何不是 0=>a 1=>b 2=>c$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 */
按照手冊中的說法, 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,PHP7新特性之foreach4 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
[x] foreach 循環(huán)對數(shù)組內(nèi)部指針不再起作用, 在PHP7之前, 當(dāng)數(shù)據(jù)通過foreach迭代時, 數(shù)組指針會移動。
版本 | 結(jié)果 | 說明 |
---|---|---|
PHP5 | int(1) int(2) bool(false) | 數(shù)組指針會移動 |
PHP7 | int(0) int(0) int(0) | 數(shù)據(jù)指針不再移動 |
[x] 按照值進(jìn)行循環(huán)時, 對數(shù)組的修改是不會影響循環(huán)。
foreach按照值進(jìn)行循環(huán)的時候(by-value), foreach是對該數(shù)組的一個拷貝進(jìn)行操作. 所以在循環(huán)過程中修改不影響循環(huán)結(jié)果
版本 | 結(jié)果 | 說明 |
---|---|---|
PHP5 | int(0) int(2) | 會將unset的數(shù)據(jù)跳過 |
PHP7 | int(0) int(1) int(2) | 對數(shù)組的改動不影響循環(huán) |
[x] 按照引用進(jìn)行循環(huán)的時候, 對數(shù)組的修改會影響循環(huán)
版本 | 結(jié)果 |
---|---|
PHP5 | int(0) int(2) |
PHP7 | int(0) int(2) |
[x] 對簡單對象plain(non-Traversable)的循環(huán)
在簡單對象的循環(huán), 不管是按照值循環(huán)還是引用循環(huán), 和按照引用對數(shù)組循環(huán)的行為是一樣的, 不過對位置的管理會更加精確
[x] 對迭代對象(Traversable objects)對象行為和之前一致
stackoverflow 上面的解釋, Traversable objects is one that implements Iterator or IteratorAggregate interface
如果一個對象實(shí)現(xiàn)了 Iterator 或者 IteratorAggregate 接口, 即可稱之為迭代對象
參考https://wiki.php.net/rfc/php7...
97fe15db4356f8fa1b3b8eb9bb1baa8141376077
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/29091.html
摘要:深入探討的簡介加深對的理解循環(huán)時動態(tài)往數(shù)組里添加數(shù)據(jù)循環(huán)時指針移動賦值執(zhí)行循環(huán)體的順序循環(huán)時調(diào)用等函數(shù)對數(shù)組兩次的使用陷阱技術(shù)水平有限,歡迎諸位指正,非常感謝注意當(dāng)時測試環(huán)境是,在中有變化 深入探討php的foreach1、foreach簡介 - http://segmentfault.com/a/119...2、加深對foreach的理解 - http://segmentfault....
摘要:已經(jīng)發(fā)布如承諾我也要開始這個系列的文章的編寫今天我想先和大家聊聊的變化在講變化的之前我們先來看看在下面是什么樣子回顧在的時候的定義如下對內(nèi)核有了解的同學(xué)應(yīng)該對這個結(jié)構(gòu)比較熟悉因?yàn)榭梢员硎疽磺兄械臄?shù)據(jù)類型所以它包含了一個字段表示這個存儲的是什 PHP7已經(jīng)發(fā)布, 如承諾, 我也要開始這個系列的文章的編寫, 今天我想先和大家聊聊zval的變化. 在講zval變化的之前我們先來看看zval在...
摘要:本文先回顧生成器,然后過渡到協(xié)程編程。其作用主要體現(xiàn)在三個方面數(shù)據(jù)生成生產(chǎn)者,通過返回數(shù)據(jù)數(shù)據(jù)消費(fèi)消費(fèi)者,消費(fèi)傳來的數(shù)據(jù)實(shí)現(xiàn)協(xié)程。解決回調(diào)地獄的方式主要有兩種和協(xié)程。重點(diǎn)應(yīng)當(dāng)關(guān)注控制權(quán)轉(zhuǎn)讓的時機(jī),以及協(xié)程的運(yùn)作方式。 轉(zhuǎn)載請注明文章出處: https://tlanyan.me/php-review... PHP回顧系列目錄 PHP基礎(chǔ) web請求 cookie web響應(yīng) sess...
摘要:眾所周知,中的聲明存在變量提升機(jī)制,因此引用了塊級作用域來強(qiáng)化對變量生命周期的控制聲明不會被提升,有幾個需要注意的點(diǎn)不能被重復(fù)聲明假設(shè)作用域中已經(jīng)存在某個標(biāo)識符無論該標(biāo)識符是通過聲明還是變量聲明,此時再使用或關(guān)鍵定聲明會拋錯此處則會拋出錯誤 眾所周知,js中的var聲明存在變量提升機(jī)制,因此ESMAScript 6引用了塊級作用域來強(qiáng)化對變量生命周期的控制let const 聲明不會被...
閱讀 1834·2021-11-24 09:39
閱讀 2302·2021-09-30 09:47
閱讀 4169·2021-09-22 15:57
閱讀 1888·2019-08-29 18:36
閱讀 3589·2019-08-29 12:21
閱讀 599·2019-08-29 12:17
閱讀 1276·2019-08-29 11:25
閱讀 734·2019-08-28 18:26