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

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

Jul 20, 2015

Download

Technology

Takaaki Hirano
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: PHP foreachでの参照渡しに潜む罠

PHPforeachでの参照渡しに潜む罠

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

foreachでループ中に配列の値を変更したいとき参照渡しにしたりしますよね

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

$array = [‘foo’, ‘bar’, ‘baz’]foreach ($array as &$value) { $value = strtoupper($value);}

var_dump($array);

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

$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"}

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

ここまで想定通り

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

ではこの配列にもう一度foreachを、今度は非参照渡しで使うと?

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

$array = [‘foo’, ‘bar’, ‘baz’]foreach ($array as &$value) { $value = strtoupper($value);}

foreach ($array as $key => $value) { $array[$key] = strtolower($value);}

var_dump($array);

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

$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"}

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

$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"} !?

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

配列が破壊されてしまう

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

どうしてこうなった

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

$valueがforeachを抜けた後も参照を保持していることが原因

どうしてこうなった

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

$valueがforeachを抜けた後も参照を保持していることが原因

どうしてこうなった

「いまいちよくわからない」 (東京都 会社員 T・H)

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

$valueがforeachを抜けた後も参照を保持していることが原因

どうしてこうなった

「いまいちよくわからない」 (東京都 会社員 T・H)

「こころにひびかない」 (東京都 会社員 T・H)

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

$valueがforeachを抜けた後も参照を保持していることが原因

どうしてこうなった

「いまいちよくわからない」 (東京都 会社員 T・H)

「こころにひびかない」 (東京都 会社員 T・H)

「おすしがたべたい」 (東京都 会社員 T・H)

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

実際何が起こっているのか

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

$array = [‘foo’, ‘bar’, ‘baz’]foreach ($array as &$value) { $value = strtoupper($value);}

// 各ループの処理開始前に何が代入されているのか?

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

$array = [‘foo’, ‘bar’, ‘baz’]foreach ($array as &$value) { $value = strtoupper($value);}

// 各ループの処理開始前に何が代入されているのか?// $value = &$array[0] = ‘foo’// $value = &$array[1] = ‘bar’// $value = &$array[2] = ‘baz’

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

$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]を変更している

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

$array = [‘foo’, ‘bar’, ‘baz’]foreach ($array as &$value) { $value = strtoupper($value);}

// ループ終了後に$valueはどうなっているのか?

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

$array = [‘foo’, ‘bar’, ‘baz’]foreach ($array as &$value) { $value = strtoupper($value);}

// ループ終了後に$valueはどうなっているのか?// $value = &$array[2] = ‘BAZ’

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

$array = [‘foo’, ‘bar’, ‘baz’]foreach ($array as &$value) { $value = strtoupper($value);}

// ループ終了後に$valueはどうなっているのか?// $value = &$array[2] = ‘BAZ’// これは$array[2]への参照なので、// $valueを変更すると$array[2]が変更される

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

$array = [‘foo’, ‘bar’, ‘baz’]foreach ($array as &$value) { $value = strtoupper($value);}

// $value = &$array[2] = ‘BAZ’

foreach ($array as $key => $value) { $array[$key] = strtolower($value);}

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

$array = [‘foo’, ‘bar’, ‘baz’]foreach ($array as &$value) { $value = strtoupper($value);}

// $value = &$array[2] = ‘BAZ’

foreach ($array as $key => $value) { $array[$key] = strtolower($value);}

// 各ループの処理開始前に何が代入されているのか?

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

$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’)

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

$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’)

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

$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’)

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

$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"}

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

回避するために

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

二回目も参照渡しにする

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

書くタイミングがずれていると忘れる危険性が高い

間に大量のコードがあると忘れる危険性が高い

別の人間が書くならば尚更

二回目も参照渡しにする

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

書くタイミングがずれていると忘れる危険性が高い

間に大量のコードがあると忘れる危険性が高い

別の人間が書くならば尚更

そもそも、「この後はこういうふうに書かないと壊れます」などという書き方自体すべきではない

二回目も参照渡しにする

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

ループを抜けたらunset($value)する

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

実はマニュアルでも推奨されているhttp://php.net/manual/ja/control-structures.foreach.php

ループを抜けたらunset($value)する

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

実はマニュアルでも推奨されているhttp://php.net/manual/ja/control-structures.foreach.php

書き忘れる危険性はある

ループを抜けたらunset($value)する

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

参照渡ししない

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

そもそも参照渡ししなければ当然起こらない

参照渡ししない

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

そもそも参照渡ししなければ当然起こらない

参照渡ししない

foreach ($array as $key => $value) { $array[$key] = strtolower($value);}

$array_lower = [];foreach ($array as $value) { $array_lower[] = strtolower($value);}

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

そもそも参照渡ししなければ当然起こらない

参照渡ししない

foreach ($array as $key => $value) { $array[$key] = strtolower($value);}

$array_lower = [];foreach ($array as $value) { $array_lower[] = strtolower($value);}

確実だがちょっと書くのが面倒な場合もある

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

わかりにくいバグの温床になるので気をつけましょう