[解決済み] PHP Foreach 参照渡し。最後の要素が重複している?(バグ?) [重複]
質問
私が書いていた簡単なphpスクリプトで、とても奇妙な動作がありました。バグを再現するために必要最小限のものに縮小しました。
<?php
$arr = array("foo",
"bar",
"baz");
foreach ($arr as &$item) { /* do nothing by reference */ }
print_r($arr);
foreach ($arr as $item) { /* do nothing by value */ }
print_r($arr); // $arr has changed....why?
?>
これが出力されます。
Array
(
[0] => foo
[1] => bar
[2] => baz
)
Array
(
[0] => foo
[1] => bar
[2] => bar
)
これはバグなのでしょうか、それとも本当に不思議な動作が起こるはずなのでしょうか?
解決方法は?
最初のforeachループの後。
$item
は、まだ何らかの値への参照であり、その値もまた
$arr[2]
. そのため、参照による呼び出しを行わない 2 番目のループの各 foreach 呼び出しは、その値を置き換えることになり、その結果
$arr[2]
を新しい値で置き換えます。
つまりループ1では、値と
$arr[2]
になります。
$arr[0]
であり、'foo'である。
ループ2、値や
$arr[2]
になります。
$arr[1]
であり、'bar'である。
ループ3では、値や
$arr[2]
になります。
$arr[2]
となり、'bar' となる(ループ2があるため)。
値'baz'は、実際には2番目のforeachループの最初の呼び出しで失われます。
出力のデバッグ
ループの各反復に対して
$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]
.
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[3]
というのは、どちらも同じ場所を指しているからです。ループが配列の 3 番目の値に到達したとき、そこには
bar
なぜなら、このループの前の繰り返しで設定されたばかりだからです。
バグなのか?
いいえ、これは参照されたアイテムの動作であり、バグではありません。というようなことを実行しているのと同じようなものでしょう。
for ($i = 0; $i < count($arr); $i++) { $item = $arr[$i]; }
foreachループは、参照されている項目を無視できるという点では、特別な性質はありません。ループの外で行うように、その都度その変数に新しい値をセットするだけです。
関連
-
[解決済み】PHPで空の値からデフォルトオブジェクトを作成する?
-
[解決済み】++と*+の意味は何ですか?
-
[解決済み】Laravel 5.2 Storage::makeDirectory($dir) でディレクトリが作成されない。
-
phpのAllowed memory size of 134217728 bytes枯渇問題の解決法
-
[解決済み] SSLエラー SSL3_GET_SERVER_CERTIFICATE:証明書の検証に失敗しました。
-
[解決済み] 変数を参照渡しする方法を教えてください。
-
[解決済み] PHPで配列から要素を削除する
-
[解決済み] foreachループの最初と最後の繰り返しを決定する方法は?
-
[解決済み】PHPの'foreach'は実際どのように動作するのですか?
-
[解決済み] リファレンス - このシンボルはPHPで何を意味するのですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] [Solved] Fatal error: メンバ関数bind_param()のbooleanに対する呼び出し [重複] [重複
-
[解決済み】予期せぬ例外。SQLSTATE[HY000] [1045] Access denied for user ****@'localhost' (using password: YES)
-
[解決済み】メッセージ。Trying to access array offset on value of type null [重複]配列のオフセットにアクセスしようとしています。
-
[解決済み] * vchiqインスタンスを開くのに失敗しました。
-
[解決済み] PHP - ストリームを開くのに失敗しました : そのようなファイルまたはディレクトリがありません。
-
phpのAllowed memory size of 134217728 bytes枯渇問題の解決法
-
[解決済み】Fatal error: mysqli_result 型のオブジェクトは使用できません [終了] 。
-
[解決済み】mysqli::query(): mysqli をフェッチできない
-
[解決済み] SSLエラー SSL3_GET_SERVER_CERTIFICATE:証明書の検証に失敗しました。
-
[解決済み】PHP foreachでの参照渡し【重複あり