摘要:本文整理自網站上的一篇文章在循環中,如果使用引用會引發非常奇怪的行為這是的一個嗎問題在我寫一個簡單的腳本時,發生了一些非常奇怪的現象。在中,如果一個內存空間是被引用的,那么當改變它的時候是直接改變這塊內存空間的值。
本文整理自 stackoverflow 網站上的一篇文章 Strange behaviour after loop by reference - Is this a PHP bug? —— 在 PHP 循環中,如果使用 引用 會引發非常奇怪的行為 - 這是 PHP 的一個 bug 嗎?
問題在我寫一個簡單的 PHP 腳本時,發生了一些非常奇怪的現象。下面是我的代碼,為了清楚的表達我的意思,我特意去掉了一些不必要的代碼:
輸出如下:
Array ( [0] => foo [1] => bar [2] => baz ) Array ( [0] => foo [1] => bar [2] => bar // 錯誤發生?? )這是 PHP 的一個 bug 嗎?PHP 中為什么會發生如此古怪的行為呢?
解析在第一個 foreach 循環結束后,$item 仍然引用(reference)著數組的最后一個元素,也就是 $arr[2]。 因此,當開始第二個循環的時候,$item 變量每次循環都會被賦一個新值。 在 php 中,如果一個內存空間是被引用的,那么當改變它的時候是直接改變這塊內存空間的值。 當改變 $item 的時候,其實也改變了 $arr[2] 的值。
因此,在第二個循環中:
第一次循環,$item 和 $arr[2] 的值變成 $arr[0],也就是 "foo"。
第二次循環,$item 和 $arr[2] 的值變成 $arr[1],也就是 "bar"。
第三次循環,$item 和 $arr[2] 的值變成 $arr[2],也就是 "bar"($arr[2] 的值不是 "baz",因為在第二次循環中變成了 "bar")。
"baz" 的值實際是在第二個循環中丟失了。
譯注:我不喜歡把 reference 翻譯成「引用」,當然了,更不能翻譯成「參考」了。每次我像別人解釋 reference 時,都會告訴他: reference 就是 alias。 比如你叫吳毅昌(呵呵,無異常),二狗子是你的別名。本著好兄弟好基友的情誼:“來,二狗子,這 100 塊錢給你吧。” 你——吳毅昌——回家一模口袋,多了 100 塊錢。 @justjavac
調試輸出我們可以修改代碼來調試并跟蹤循環的執行細節。 我們可以輸出 $item 的值,并且遞歸的輸出數組 $arr。
當第一個循環運行時,我們可以看到這樣的輸出:
foo Array ( [0] => foo [1] => bar [2] => baz ) bar Array ( [0] => foo [1] => bar [2] => baz ) baz Array ( [0] => foo [1] => bar [2] => baz )在循環結束后,$item 和 $arr[2] 指向同一個內存區域。
當第二個循環運行時,我們看到這樣的輸出:
foo Array ( [0] => foo [1] => bar [2] => foo ) bar Array ( [0] => foo [1] => bar [2] => bar ) bar Array ( [0] => foo [1] => bar [2] => bar )在這次循環中,需要注意隨著每次 $item 被賦予一個新值, $arr[2] 也會被賦值為和 $item 相同的值,因為它們都仍然指向相同的內存空間(譯注:原文寫的是 $arr[3],疑為原作者筆誤。@justjavac)。 當循環到達數組的第三個值時,它包含的值是 bar,因為它的值在前兩次循環中,被修改了。
還有疑問也許你覺得,我僅僅是執行了一個空循環 foreach ($arr as &$item){},循環體里面什么都沒有做,為什么數組元素卻改變了?
可能你覺得這個代碼應該等價于
for ($i = 0; $i < count($arr); $i++) { // do nothing }其實不對,代碼應該等價于:
for ($i = 0; $i < count($arr); $i++) { $item = $arr[$i]; }也就是說, 在 foreach 循環中,隱含了一個賦值運算,唯一不同的時, 在賦值過程中,我們使用了引用,所以在第一個循環中,無意中修改了正在循環的數組內部的元素。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/20609.html
摘要:在的官方手冊中寫道支持風格的前后遞增與遞減運算符。第一個注意事遞增遞減運算符不影響布爾值。遞增遞減布爾值遞增遞減在處理字符變量的算數運算時,沿襲了的習慣,而非的。還有一個注意事項遞增遞減其他字符變量則無效,原字符串沒有變化。 在 PHP 的官方手冊中寫道: PHP 支持 C 風格的前/后遞增與遞減運算符。 第一個注意事:遞增/遞減運算符不影響布爾值。遞減 NULL 值也沒有...
摘要:中基礎中的三大坑,遍歷,引用機制,數組。今天我們在講講中的一些奇怪現象。本文適合有一定基礎的。運行流程共用一個結構體開始遍歷數組,進行判斷,拷貝數組是一個新的結構體,操作的是新的結構體。那么遍歷數組時,全程與原數組無關。 PHP中基礎中的三大坑,foreach遍歷,引用機制&,數組。 今天我們在講講foreach中的一些奇怪現象。 在講解之前,可以先看看我其他相關的文章,屬于同一個大的...
摘要:總結垃圾回收機制以的引用計數機制為基礎以前只有該機制同時使用根緩沖區機制,當發現有存在循環引用的時,就會把其投入到根緩沖區,當根緩沖區達到配置文件中的指定數量后,就會進行垃圾回收,以此解決循環引用導致的內存泄漏問題開始引入該機制 php垃圾回收機制,對于PHPer來說是一個不陌生但是又不是很熟悉的內容。那么php是怎么實現對不需要的內存進行回收的呢? php變量的內部存儲結構 首先還是...
摘要:背景項目中通過遠程調用服務框架調用了許多其它的服務其中有一個服務需要升級其升級不是版本上的升級而是整個服務重新取了一個名字使用的也是全新的包但是調用的方法沒有改變因此在升級時只是在調用服務類中修改了調用地址和調用返回實體由改為該中返回該調用 背景 項目中通過遠程調用服務框架調用了許多其它的服務,其中有一個服務wx/subscribe/contract/CircleService 需要升...
摘要:這種行為比最初出現的問題更為棘手,同時也是一種常見的錯誤源。這意味著這個數組的一份拷貝將會被返回,因此被調函數與調用者所訪問的數組并不是同樣的數組實例。 showImg(https://segmentfault.com/img/bV7reP?w=620&h=620); PHP 語言讓 WEB 端程序設計變得簡單,這也是它能流行起來的原因。但也是因為它的簡單,PHP 也慢慢發展成一個相對...
閱讀 2471·2021-11-17 09:33
閱讀 758·2021-11-04 16:13
閱讀 1329·2021-10-14 09:50
閱讀 691·2019-08-30 15:53
閱讀 3657·2019-08-30 14:18
閱讀 3268·2019-08-30 14:14
閱讀 2093·2019-08-30 12:46
閱讀 3178·2019-08-26 14:05