PHP 開発中にこの問題に遭遇し、問題を次のように単純化しました:
$arr = array(1,2,3,4,5,6); $n = 3; foreach($arr as $key=>$val){ if($val == $n) break; } while(list($k,$v) = each($arr)){ echo $v; }
each() ループは配列ポインターを自動的にリセットしないため、上記のコード実行の出力は次のとおりです: 456
ただし、関数に記述された結果は次のように異なります。
$arr = array(1,2,3,4,5,6); $n = 3; test1($arr,$n); function test1($arr,$n) { foreach($arr as $key=>$val){ if($val == $n) break; } while(list($k,$v) = each($arr)){ echo $v; } }
コードの実行結果は次のとおりです: 123456
実際、これはすべて PHP の「コピーオンライト」変数が原因であると言えるのはなぜでしょうか。分析を見てみましょう。
「コピーオンライト」とは何ですか?
これは例です:
$arr = array(1,2,3,4,5,6); $n = 3; $arr1 = $arr; // 此时并没有复制,是引用关系 debug_zval_dump($arr); // recount = 3,因为debug_zval_dump有一次 $arr[0] = 1; // 此时有写操作,要分离 debug_zval_dump($arr); // recount = 2
PHP マニュアルには次のように書かれています:
配列を別の配列に代入すると元の配列ポインタがリセットされるため、上記の例でループ内で $fruit を別の変数に代入すると無限ループが発生します。
PHP マニュアルにはそれぞれの導入について記載されていますが、実際には、配列変数が分離されると配列ポインターがリセットされることを意味します。
$arr = array(1,2,3,4,5,6); $n = 3; $arr1 = $arr; // 此时并没有复制,是引用关系,可以看作是函数复制调用 foreach($arr as $key=>$val){ if($val == $n) break; } debug_zval_dump($arr); // refcount = 3 list($k,$v) = each($arr); // 因为each会改变数组的指针,所以还是写操作,存在分离 echo $v; debug_zval_dump($arr); // refcount = 2
&演算に関しては「変数分離」が存在しないか、&演算と同時に「変数分離」が完了します。
$arr = array(1,2,3,4,5,6); $n = 3; $arr1 = &$arr; // 引用,“变量分离”是在&操作的同时完成 foreach($arr as $key=>$val){ if($val == $n) break; } debug_zval_dump($arr); // refcount = 2 list($k,$v) = each($arr); // 不存在变量分离 echo $v; debug_zval_dump($arr); // refcount = 2
同じ効果も利用できます:
$arr = array(1,2,3,4,5,6); $n = 3; $arr1 = $arr; // 此时并没有复制,是引用关系,可以看作是函数复制调用 foreach($arr as $key=> &$val){ // 存在可能写的情况,变量分离 if($val == $n) break; } debug_zval_dump($arr); // refcount = 2 list($k,$v) = each($arr); // 不存在变量分离 echo $v; debug_zval_dump($arr); // refcount = 2
したがって、それぞれを使用する前に、上記の問題を回避するために、reset (参照がある場合、変数分離が発生します) を使用して配列ポインタを一律にリセットするのが最善です。