PHP foreachでの参照渡しに潜む罠

529
-1

Published on

Be careful to passing value by reference in foreach.

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
529
On Slideshare
0
From Embeds
0
Number of Embeds
6
Actions
Shares
0
Downloads
2
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

PHP foreachでの参照渡しに潜む罠

  1. 1. PHP foreachでの参照渡しに潜む罠
  2. 2. foreachでループ中に配列の値を変更したいとき 参照渡しにしたりしますよね
  3. 3. $array = [‘foo’, ‘bar’, ‘baz’] foreach ($array as &$value) { $value = strtoupper($value); } var_dump($array);
  4. 4. $array = [‘foo’, ‘bar’, ‘baz’] foreach ($array as &$value) { $value = strtoupper($value); } var_dump($array); array(3) { [0]=> string(3) "FOO" [1]=> string(3) "BAR" [2]=> &string(3) "BAZ" }
  5. 5. ここまで想定通り
  6. 6. ではこの配列にもう一度foreachを、 今度は非参照渡しで使うと?
  7. 7. $array = [‘foo’, ‘bar’, ‘baz’] foreach ($array as &$value) { $value = strtoupper($value); } foreach ($array as $key => $value) { $array[$key] = strtolower($value); } var_dump($array);
  8. 8. $array = [‘foo’, ‘bar’, ‘baz’] foreach ($array as &$value) { $value = strtoupper($value); } foreach ($array as $key => $value) { $array[$key] = strtolower($value); } var_dump($array); array(3) { [0]=> string(3) "foo" [1]=> string(3) "bar" [2]=> &string(3) "bar" }
  9. 9. $array = [‘foo’, ‘bar’, ‘baz’] foreach ($array as &$value) { $value = strtoupper($value); } foreach ($array as $key => $value) { $array[$key] = strtolower($value); } var_dump($array); array(3) { [0]=> string(3) "foo" [1]=> string(3) "bar" [2]=> &string(3) "bar" } !?
  10. 10. 配列が破壊されてしまう
  11. 11. どうしてこうなった
  12. 12. $valueがforeachを抜けた後も参照を保持していることが原因 どうしてこうなった
  13. 13. $valueがforeachを抜けた後も参照を保持していることが原因 どうしてこうなった 「いまいちよくわからない」 (東京都 会社員 T・H)
  14. 14. $valueがforeachを抜けた後も参照を保持していることが原因 どうしてこうなった 「いまいちよくわからない」 (東京都 会社員 T・H) 「こころにひびかない」 (東京都 会社員 T・H)
  15. 15. $valueがforeachを抜けた後も参照を保持していることが原因 どうしてこうなった 「いまいちよくわからない」 (東京都 会社員 T・H) 「こころにひびかない」 (東京都 会社員 T・H) 「おすしがたべたい」 (東京都 会社員 T・H)
  16. 16. 実際何が起こっているのか
  17. 17. $array = [‘foo’, ‘bar’, ‘baz’] foreach ($array as &$value) { $value = strtoupper($value); } // 各ループの処理開始前に何が代入されているのか?
  18. 18. $array = [‘foo’, ‘bar’, ‘baz’] foreach ($array as &$value) { $value = strtoupper($value); } // 各ループの処理開始前に何が代入されているのか? // $value = &$array[0] = ‘foo’ // $value = &$array[1] = ‘bar’ // $value = &$array[2] = ‘baz’
  19. 19. $array = [‘foo’, ‘bar’, ‘baz’] foreach ($array as &$value) { $value = strtoupper($value); } // 各ループの処理開始前に何が代入されているのか? // $value = &$array[0] = ‘foo’ // $value = &$array[1] = ‘bar’ // $value = &$array[2] = ‘baz’ // $valueを変更して参照先の$array[n]を変更している
  20. 20. $array = [‘foo’, ‘bar’, ‘baz’] foreach ($array as &$value) { $value = strtoupper($value); } // ループ終了後に$valueはどうなっているのか?
  21. 21. $array = [‘foo’, ‘bar’, ‘baz’] foreach ($array as &$value) { $value = strtoupper($value); } // ループ終了後に$valueはどうなっているのか? // $value = &$array[2] = ‘BAZ’
  22. 22. $array = [‘foo’, ‘bar’, ‘baz’] foreach ($array as &$value) { $value = strtoupper($value); } // ループ終了後に$valueはどうなっているのか? // $value = &$array[2] = ‘BAZ’ // これは$array[2]への参照なので、 // $valueを変更すると$array[2]が変更される
  23. 23. $array = [‘foo’, ‘bar’, ‘baz’] foreach ($array as &$value) { $value = strtoupper($value); } // $value = &$array[2] = ‘BAZ’ foreach ($array as $key => $value) { $array[$key] = strtolower($value); }
  24. 24. $array = [‘foo’, ‘bar’, ‘baz’] foreach ($array as &$value) { $value = strtoupper($value); } // $value = &$array[2] = ‘BAZ’ foreach ($array as $key => $value) { $array[$key] = strtolower($value); } // 各ループの処理開始前に何が代入されているのか?
  25. 25. $array = [‘foo’, ‘bar’, ‘baz’] foreach ($array as &$value) { $value = strtoupper($value); } // $value = &$array[2] = ‘BAZ’ foreach ($array as $key => $value) { $array[$key] = strtolower($value); } // 各ループの処理開始前に何が代入されているのか? // ($value = &$array[2]) = ($array[0] = ‘FOO’)
  26. 26. $array = [‘foo’, ‘bar’, ‘baz’] foreach ($array as &$value) { $value = strtoupper($value); } // $value = &$array[2] = ‘BAZ’ foreach ($array as $key => $value) { $array[$key] = strtolower($value); } // 各ループの処理開始前に何が代入されているのか? // ($value = &$array[2]) = ($array[0] = ‘FOO’) // ($value = &$array[2]) = ($array[1] = ‘BAR’)
  27. 27. $array = [‘foo’, ‘bar’, ‘baz’] foreach ($array as &$value) { $value = strtoupper($value); } // $value = &$array[2] = ‘BAZ’ foreach ($array as $key => $value) { $array[$key] = strtolower($value); } // 各ループの処理開始前に何が代入されているのか? // ($value = &$array[2]) = ($array[0] = ‘FOO’) // ($value = &$array[2]) = ($array[1] = ‘BAR’) // ($value = &$array[2]) = ($array[2] = ‘BAR’)
  28. 28. $array = [‘foo’, ‘bar’, ‘baz’] foreach ($array as &$value) { $value = strtoupper($value); } // $value = &$array[2] = ‘BAZ’ foreach ($array as $key => $value) { $array[$key] = strtolower($value); } var_dump($array); array(3) { [0]=> string(3) "foo" [1]=> string(3) "bar" [2]=> &string(3) "bar" }
  29. 29. 回避するために
  30. 30. 二回目も参照渡しにする
  31. 31. 書くタイミングがずれていると忘れる危険性が高い 間に大量のコードがあると忘れる危険性が高い 別の人間が書くならば尚更 二回目も参照渡しにする
  32. 32. 書くタイミングがずれていると忘れる危険性が高い 間に大量のコードがあると忘れる危険性が高い 別の人間が書くならば尚更 そもそも、「この後はこういうふうに書かないと壊れます」 などという書き方自体すべきではない 二回目も参照渡しにする
  33. 33. ループを抜けたらunset($value)する
  34. 34. 実はマニュアルでも推奨されている http://php.net/manual/ja/control-structures.foreach.php ループを抜けたらunset($value)する
  35. 35. 実はマニュアルでも推奨されている http://php.net/manual/ja/control-structures.foreach.php 書き忘れる危険性はある ループを抜けたらunset($value)する
  36. 36. 参照渡ししない
  37. 37. そもそも参照渡ししなければ当然起こらない 参照渡ししない
  38. 38. そもそも参照渡ししなければ当然起こらない 参照渡ししない foreach ($array as $key => $value) { $array[$key] = strtolower($value); } $array_lower = []; foreach ($array as $value) { $array_lower[] = strtolower($value); }
  39. 39. そもそも参照渡ししなければ当然起こらない 参照渡ししない foreach ($array as $key => $value) { $array[$key] = strtolower($value); } $array_lower = []; foreach ($array as $value) { $array_lower[] = strtolower($value); } 確実だがちょっと書くのが面倒な場合もある
  40. 40. わかりにくいバグの温床になるので 気をつけましょう
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×