PHPの変数には、C, C++などのポインタ変数と同じ動きをする変数があります。リファレンス(参照)と言います。
これ、ポインタをPHPに実装してるんだと思いがちですが、しくみはまったくちがう。
かくいうボクもCから出発した人間で、なぜか何度も勘違いしてしまう。
まずはリファレンスの動きを見てみよう。
まず最初に、サンプルコードでリファレンスがどういうものか見てみましょう。
<?php
$g_test = 'sample data';
function test(&$param) {
$param = 'change sample data';
}
echo $g_test . PHP_EOL;
test($g_test);
echo $g_test . PHP_EOL;
sample data
change sample data
本来、関数のパラメータの変数($param)は、呼び出し側で渡される変数($g_test)の値を入れた別物の変数なので、関数内で値を変更しても $g_test には影響ないはずです。
しかし、変数をリファレンスとして使うと $g_test の値が変わる。
これ、C, C++出身の人はコンマ秒でポインタ変数だと思っちゃいます。アンパサンド(&)を使ってるし。
リファレンス変数はアドレスを格納していない。ただのエイリアス。
リファレンスとポインタを混合してしまう原因はアンパサンド(&)にあります。
ポインタでは & を付けるとその変数の値ではなく、値が格納されているメモリ上のアドレスを参照します。
一方、リファレンスは元変数のエイリアスを意味します。要は変数名が違うだけで参照しているところは同じ。
サンプルでは、$g_test の別名変数 $param が用意されてるだけ。
リファレンス変数では、プログラマが $param を変更しているようで、じっさいは元の $g_test をイジってることになる。
PHP公式ドキュメントでも、リファレンスの値はアドレスではない、ポインタとはちがう、ただのエイリアス、と書いてます。
Unixのハードリンクみたいなもの、とも言っている。
(Linuxでも同じ。Windowsではファイルやフォルダのショートカットのこと。)
PHP公式ドキュメント
リファレンス = リファレンス で代入はできない。
リファレンス変数に代入できるのは値そのものです。もしくは普通の変数。ここがポインタとの違い。
(むしろポインタ変数はポインタ変数に代入するのが一般的。)
<?php
$g_test = 'sample data';
function test(&$param) {
$local = 'change sample data';
$param = &$local;
}
echo $g_test . PHP_EOL;
test($g_test);
echo $g_test . PHP_EOL;
sample data
sample data
関数内で値を変更しても何も起きません。正解は "$param = $local;" です。
PHP公式ドキュメント
リファレンスは ++ や -- しても計算するだけ。
当たり前ですが、リファレンス変数の値を足し算、引き算しても、ただ値が計算されて変わるだけです。
ポインタでは足し算、引き算でアドレス移動して変数が指し示す先を変えることができます。
(変数が見る先を変更しているだけで値は変わらない。)
しかし、リファレンスにはアドレスが入ってないので、値そのものを計算して変えてしまう。
ここが一番注意するところかな。値を変更するつもりはないのに変わるので。
PHP公式ドキュメント