ホームページ  >  記事  >  バックエンド開発  >  PHPループ内の「参照」によって引き起こされる奇妙な問題

PHPループ内の「参照」によって引き起こされる奇妙な問題

WBOY
WBOYオリジナル
2016-07-25 08:46:29943ブラウズ

この記事は、stackoverflow ウェブサイトの記事「参照によるループ後の奇妙な動作 - これは PHP のバグですか?」から編集されたものです。 PHP ループ内で references を使用すると、非常に奇妙な動作が発生します。これは PHP のバグですか?

質問

簡単な PHP スクリプトを書いているときに、非常に奇妙なことが起こりました。以下は私のコードです。私が言いたいことを明確に表現するために、いくつかの不要なコードを意図的に削除しました。

  1. $arr = array("foo",
  2. "bar",
  3. "baz");
  4. foreach ($arr as &$item) { /* 参照によって何も実行しません */ }
  5. print_r($arr);
  6. foreach ($arr as $item) { /* 値によっては何もしません */ }
  7. print_r($arr) // $arr が変更されました...なぜですか?
;
コードをコピー
出力は次のとおりです:

    配列
  1. (
  2. [0] => foo
  3. [1] => bar
  4. [2] => baz
  5. )
  6. 配列
  7. (
  8. [0] => foo
  9. [1] = > バー
  10. [2] => バー // エラーが発生しました
これは PHP のバグですか? PHP ではなぜこのような奇妙な動作が起こるのでしょうか? 解析する 最初の foreach ループが終了した後も、$item は配列の最後の要素である $arr[2] を参照します。 したがって、2 番目のループを開始すると、ループを通過するたびに $item 変数に新しい値が割り当てられます。 PHPでは、メモリ空間が参照されている場合、それを変更すると、そのメモリ空間の値が直接変更されます。 $item が変更されると、$arr[2] の値も変更されます。

つまり、2 番目のループでは次のようになります:

初めてループを通過すると、$item と $arr[2] の値は $arr[0]、つまり 'foo' になります。 2 番目のループでは、$item と $arr[2] の値が $arr[1]、つまり 'bar' になります。 3 番目のループでは、$item と $arr[2] の値は、「bar」である $arr[2] になります (2 番目のループでは、$arr[2] の値は「baz」ではありません) 「バー」になります)。

「baz」の値は実際には 2 番目のループで失われます。

翻訳メモ

: 私は、reference を「引用」に訳すのは好きではありません。もちろん、「参照」はおろか。私が誰かにリファレンスを説明するときはいつも、「

リファレンスはエイリアスです

」と伝えます。 たとえば、あなたの名前はウー・イーチャン (笑、珍しいものではありません) で、エルゴウジはあなたの別名です。良き兄弟、良き友人の友情の精神で、「さあ、エルグージ、この100元あげましょう。」 あなた - ウー・イーチャン - まったく同じポケットを持って家に帰りますが、100 元追加されます。 @justjavac デバッグ出力 コードを変更して、ループの実行の詳細をデバッグおよびトレースできます。 $item の値を出力し、配列 $arr を再帰的に出力できます。 最初のループが実行されると、次のような出力が表示されます:

foo
Array ( [0] => foo [1] => bar [2] => baz )
    bar
  1. Array ( [0] => foo [1] => bar [2] => baz )
  2. baz
  3. Array ( [0] => foo [1] => bar [2] => baz )
  4. コードをコピーします
ループが終了すると、$item と $arr[2] は同じメモリ領域を指します。 2 番目のループが実行されると、次の出力が表示されます:

foo
Array ( [0] => foo [1] => bar [2] => foo )
    bar
  1. Array ( [0] => foo [1] => bar [2] => bar )
  2. bar
  3. Array ( [0] => foo [1] => bar [2] => bar )
  4. コードをコピーします
このループでは、$item に新しい値が割り当てられるたびに、$arr[2] にも $item と同じ値が割り当てられることに注意してください。これは、両方とも同じメモリ空間を指しているためです (注釈: 原文) $arr[3] を読み取りますが、これは元の作成者 @justjavac による事務上のミスであると考えられます)。 ループが配列内の 3 番目の値に到達すると、値 bar が含まれます。これは、その値が前の 2 つのループ中に変更されたためです。 まだ質問があります 空のループ foreach ($arr as &$item){} を実行しただけで、ループ本体では何も行われていないのに、なぜ配列要素が変更されたのかと思われるかもしれません。

おそらくこのコードは

と同等であると思われるかもしれません

for ($i = 0; $i < count($arr); $i++) {
// 何もしない
}
  1. コードをコピー
実際には、それは正しくありません。コードは次と同等である必要があります:

for ($i = 0; $i < count($arr); $i++) {
$item = $arr[$i]
}
  1. コードをコピーします

言い換えると、 foreach ループでは、代入操作は暗黙的であるということだけです。 代入プロセス中に参照を使用したため、最初のループでループ中の配列内の要素を誤って変更してしまいました。

PHP


声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。