PHPのforeachで引用を使う時に注意するべき問題と解決方法


一、問題はまず例を見ます。
<?php$ar=array(1,2,3)var_dump($ar)foreach($ar as&$v){foreach($aras$v)}v ar_dump($ar);出力:
array(3){  [0"=>  int(1)  [1)=>  int(2)  [2)=>  int(3)}array(3){  [0"=>  int(1)  [1)=>  int(2)  [2)=>  &int(2)}?なぜ賦操作が行われていないのですか?配列の最後の要素の値が変わったのですか?
私はとっくにこの問題を発見しました。最初はPHPのバグだと思いましたが、放置していました。foreachでは引用を使わないで大丈夫です。foreachドルk=>$vを使って、そして元の配列を変えて、少し効率を失いました。
二、分析
今日は時間がかかりました。参考中の文章を見て、少し分かりました。
最初の参照を使用したforeachを実行するときは、最初に$vが$ar[0]の記憶空間を指し、空間メモリが1,foreachの終わりには$vが$ar[2]の記憶空間を指し、空間メモリが3を記憶している。次は2番目のforeachを実行します。最初のforeachとは違って、2番目のforeachは引用を使用していません。そうすると、赋値方式です。これからは、$arの値は$vに順次与えられます。最初の要素を行うときは、$ar[0]を$vに割り当てます。問題はここにあります。最初のforeachを実行したばかりのために、$vは新しい変数ではなく、既に存在している、$ar[2]を指すその参照です。そうすると、$vを賦課するときは、$ar[0]=1を$ar[2]の実際の記憶空間に書き込んで、$ar[2]を賦課するのに相当します。このように類推すると、2番目のforeachが実行した結果、配列の最後の要素が最後から2番目の要素の値になりました。参考文献2には詳細な概略図があります。
これが間違いだとすれば、エラーの原因は参照変数の使用にあります。変数が他の変数に向けられている場合、参照変数の値を変更すると、当然彼が指す他の変数に影響を及ぼします。単独では誰でも分かりますが、このforeachの例では、偶然にも同じ変数が2回使用されています。前回は引用された身分で、次は普通の変数の身分です。予想外の効果があります。PHPの開発者も、この場合は言語の特性によるもので、バグではないと考えています。確かに、この問題を修復するには、一つの方法はforeachを特殊処理する以外に、もう一つはforeachの中の$vの作用領域を制限することです。この二つの方法は現在のPHPの言語特性と一致しないので、開発者は変えたくないですが、公式文書でWarningで説明しました。
三、解決方法
簡単ですが、完璧とは言えません。引用されたforeachを使った後、unsetが$vを落としました。
<?php$ar=array(1,2,3)var_dump($ar)foreach($ar as&$v){}unset($v)foreach($ar as$v){}v ar_dump($ar);実行結果:
array(3){  [0"=>  int(1)  [1)=>  int(2)  [2)=>  int(3)}array(3){  [0"=>  int(1)  [1)=>  int(2)  [2)=>  int(3)}
参照
Bug_foreachby reference corupts the array:https://bugs.php.net/bug.php?id=29992References and foreach:http://schlueters.de/blog/archives/141-References-and-foreach.html