初めに
記事を読んでいただきありがとうございます。
一月に未経験で就職したヤマウチです。
ここでは僕が勉強の中で関心を抱いたことに関して、アウトプット感覚で記事を書います。
記事に関するフィードバック等いいただけると幸いでございます。
今回の記事について
さて、今回の記事についてですが、題名にもあります通り「PHP参照渡しとforeach」について私なりにまとめましたので共有させていただきます。
この記事を読み進める前にPHP 参照渡しを試しに使ってみたよって話を読んでいただけますと幸いです。
foreach構文
早速foreach構文に関する注意点をご紹介します。
$numbers = [1, 2, 3, 4];
foreach ($numbers as &$number) {
$number = "「{$number}」";
}
echo '<pre>';
var_dump($numbers);
echo '</pre>';
// 結果
// array(4) {
// [0]=>
// string(7) "「1」"
// [1]=>
// string(7) "「2」"
// [2]=>
// string(7) "「3」"
// [3]=>
// &string(7) "「4」"
// }
上記のようにforeach構文で要素変数を参照すると、ループ内で値を書き換えることができます。
しかし、次に紹介するようなケースでは注意が必要になります。
$numbers = [1, 2, 3, 4];
foreach ($numbers as &$number) {
$number = "「{$number}」";
}
foreach ($numbers as $number) {
echo '<pre>';
echo $number;
echo '</pre>';
}
// 結果
// 「1」
// 「2」
// 「3」
// 「3」
初めに内容を書き換えた変数を再度ループ内で表示させてみました。
見て頂くとわかる通り、$numbers[3]
結果が、$numbers[2]
の値と重複しており、最終要素の参照がうまくいっていません。うまくいっていないというよりかは、ループ内でどういったことが起っているのかを紐解いていくと必然とも言えます。
foreach構文の中身をより詳しく
foreach構文の中身を分解して表示させてみます。
$numbers = [1, 2, 3, 4];
$number = &$numbers[0]; // $numberが、$numbers[0]の別名となる
$number = "「{$number}」";
$number = &$numbers[1]; // $numberが、$numbers[1]の別名となる
$number = "「{$number}」";
$number = &$numbers[2]; // $numberが、$numbers[2]の別名となる
$number = "「{$number}」";
$number = &$numbers[3]; // $numberが、$numbers[3]の別名となる
$number = "「{$number}」";
// ---------------------------------------------------------
// 上記ループを抜けた時点で$numberは、$number[3]を指したままである。
// そのため、二回目のループでは次のようなことが起こる。
// ---------------------------------------------------------
$number = $numbers[0]; // $numbers[3] = $numbers[0] 同じ意味
echo $number;
// 結果
// 「1」
$number = $numbers[1]; // $numbers[3] = $numbers[1] 同じ意味
echo $number;
// 結果
// 「2」
$number = $numbers[2]; // $numbers[3] = $numbers[2] 同じ意味
echo $number;
// 結果
// 「3」
$number = $numbers[3]; // $numbers[3] = $numbers[3] 同じ意味
echo $number;
// 結果
// 「3」
二回目のループの最後をもう少し詳しくわかりやすく説明すると、
三回目で$numbers[3] = $numbers[2]
としているので、実質三回目は
$numbers[2] = $numbers[2]
といったことになる。
初めてですと意味わからなくなりますよね。。。(我高卒也)
解決策
ループ終了後unset()
参照渡しのループが終了後、値の変数をunset()で破棄することにより、参照を解除できます。
$numbers = [1, 2, 3, 4];
foreach ($numbers as &$number) {
$number = "「{$number}」";
}
unset($number);
foreach ($numbers as $number) {
echo '<pre>';
echo $number;
echo '</pre>';
}
// 結果
// 「1」
// 「2」
// 「3」
// 「4」
まとめ
foreachで参照渡しを使用した際の挙動に加え、参照渡しについての理解を深めることができました。
ですが、参照渡しを利用しなくても良い場面で利用してしまうとかえって混乱を巻き起こす原因となることもありますので、現代において非推奨とされるケースが多いです。
ですので、実際に業務で使う際には、当たり前ではありますがきちんと挙動を把握した上で使用すること及び、他者に混乱を招くことがないような記述を心がけていきたいと思います。