問題描述:遍歷陣列時,改變了陣列的值,陣列遍歷完成後,陣列的指標指向了第二個元素,當發生這種情況時,會對後續通過指標遍歷陣列產生影響。
<?
$arrd = array('0'=>'a','1'=>'b','2'=>'c');
echo key($arrd)."
";foreach($arrd as $intk => $val)
echo(key($arrd));
?>
輸出結果如下:
0
1
因此再次通過指標遍歷陣列的時候會發現$arrd的第乙個值就迴圈不出來了。
其實問題很好解決,在foreach之後,直接用reset()方法將$arrd的指標重置一下就可以了,但導致問題的原因才是值得關注的,在做了一些搜尋和閱讀的工作之後,總結問題原因如下,首先,先知道幾個php處理賦值遍歷等動作的原則:
1,php在變數賦值時候的記憶體使用策略:寫時複製(copy on write, cow),當用賦值方法把乙個變數值賦給另乙個變數時,由於這兩個變數值相同,因此公用同一記憶體,當其中乙個變數值發生變化時候,才會重新為值變化的變數申請記憶體,已達到節省記憶體的目的;
2,foreach遍歷陣列時,實際上是遍歷的陣列的乙個拷貝,並且在開始遍歷之前會把指標指向拷貝的開始;
3,在發生寫時複製時候,指標的位置也會一併被複製;
針對規則1 的驗證
<?
echo "初始記憶體情況:".memory_get_usage()."
";$foo = str_repeat('aaa', 10000);
echo "使用變數\$foo之後的記憶體:".memory_get_usage()."
";$bar = $foo;
echo "將變數\$foo拷貝給\$bar後的記憶體:".memory_get_usage()."
";$bar = str_repeat('aaa', 10000);
echo "對\$bar值修改後使用的記憶體:".memory_get_usage()."
";?>
輸出結果如下:
初始記憶體情況:118912
使用變數$foo之後的記憶體:149008
將變數$foo拷貝給$bar後的記憶體:149056
對$bar值修改後使用的記憶體:179104
針對規則2的驗證
<?
$a = array('a','b','c');
next($a);
foreach($a as $v)
?>
輸出結果如下
a
bc
針對規則3的驗證
<?
$a = array (1,2,3);
next($a);
$b = $a;//同一記憶體
$b = 4;//$b被開闢了新的儲存空間,指標與之前儲存空間的一致
echo current($b);
?>
輸出結果如下
2
然後來看產生最初問題的原因:
1. foreach 迴圈遍歷 $arrd 時,php建立了乙個 $arrd 的拷貝a(a是不可見的,只是為了描述方便 ),但是由於此時a和 $arrd 值一樣,所以,共用同乙個記憶體;
2.執行 foreach時候,先把a中第乙個指標所在的key和value分別賦值給 $a 和 $b,同時指標後移一位,由於此時a和 $arrd 共用同一記憶體,此時 $arrd 的指標也指向了第二個值;
3.當執行到$a = 'd';時,由於 $arrd 的值發生改變,此時系統給 $arrd分配了其他記憶體,而同時,其指標指向也被拷貝到新記憶體中;而之後的遍歷過程中,a和$arrd相當於兩個完全不同的變數,不同值,不同儲存位址,a指標的移動已經無法影響 $arrd 指標的變化,因此當 a 被遍歷完成後,$arrd的指標仍然被留在第二個值的位置。
PHP對陣列兩次foreach的使用陷阱
1.兩次迴圈如果不實用引用列印結果沒有任何問題 array a b c foreach array as value foreach array as value var dump array 執行結果 array 3 2.當第一次迴圈使用引用後會出現如下bug 如下 array a b c for...
PHP 陣列 foreach用法
foreach用於陣列 foreach僅能用於陣列,每次迴圈中,當前單元的鍵名也會在每次迴圈中被賦給變數 key。當前單元的值被賦給 value 並且陣列內部的指標向前移一步。有兩種語法 foreach array expression as value statement foreach arra...
PHP中對陣列進行排序
測試一 array array array id 1,name a array id 5,name b array id 3,name c 按列id的值進行排序 foreach array as key row 把 data 作為最後乙個引數,以通用鍵排序 print r array array m...