PHPの参照とは
公式マニュアルによると以下のように説明されています。
PHP において、リファレンスとは同じ変数の内容を異なった名前で コールすることを意味します。これは C のポインタとは異なります。 リファレンスを使ってポインタの演算をすることはできませんし、 リファレンスは実メモリのアドレスでもありません。詳細は リファレンスが行わないこと を参照ください。 そうではなく、リファレンスはシンボルテーブルのエイリアスです。 PHP では、変数名と変数の内容は異なっており、 このため、同じ内容は異なった複数の名前を有する事が可能であることに 注意してください。最も良く似ているのは、Unix のファイル名とファイルの 関係です。この場合、変数名はディレクトリエントリ、変数の内容は ファイル自体に対応します。リファレンスは、Unix ファイルシステムの ハードリンクのようなものであると考えられます。
PHPのマニュアルでは参照のことをリファレンスと表記していますが、参照と記載したほうがなじみ深いので、ここでは参照と統一して記載します。
PHPの参照は、C言語のポインタのようにメモリのアドレスが格納されているのではなく、呼び出し元の変数のエイリアス(別名)として機能するようです。
参照渡しについて
変数の前に「&」をつけることによって、その変数に格納されている値を呼び出し先の変数と共有することができます。
実際に参照渡しを行い、挙動を確認してみましょう。
<?php
$value = 'あいうえお';
$result = &$value; // $valueを参照渡し
$result = 'かきくけこ';
var_dump($value);
?>
3行目で$valueを$resultに参照渡しをし、4行目で$resultの値を変更しています。
この状態で$resultの参照元である$valueをvar_dumpで出力してみます。
string(15) "かきくけこ"
$resultに参照渡しで格納された$valueの値も変更されました。
$valueと$resultで値の共有がされていることが分かると思います。
参照渡しを行わないとどうなるでしょうか。
<?php
$value = 'あいうえお';
$result = $value; // 参照渡しを行わない
$result = 'かきくけこ';
var_dump($value);
?>
var_dumpで$valueを確認すると次のように出力されます。
string(15) "あいうえお"
3行目で参照渡しを行わないため、$valueの値がコピーされて$resultに格納されたことにより、$valueの値は変更されませんでした。
※PHPの変数は、「コピーオンライト」と呼ばれるメモリを節約する仕組みにより、変数の値を変更した場合に複製されます。test2.phpのコードだと、3行目までは$valueと$resultは同じ値を参照していますが、4行目で$result値の変更があったタイミングで、3行目の$resultに格納されている$valueが複製されます。
配列も参照渡しを使うことができます。
<?php
$a = array('あ','い','う', 'え', 'お');
$b = &$a;
$b[2] = 'く';
var_dump($a);
?>
実行結果
array(5) {
[0]=>
string(3) "あ"
[1]=>
string(3) "い"
[2]=>
string(3) "く"
[3]=>
string(3) "え"
[4]=>
string(3) "お"
}
オブジェクトはデフォルトで参照渡しが使われています。
<?php
$obj = new stdClass();
$obj->suzuki = '鈴木';
$ref = $obj;
$ref->suzuki = '佐藤';
echo $obj->suzuki;
?>
実行結果
佐藤
関数は仮引数に参照渡しをすることで、参照元の変数の値を変更することができます。
<?php
function hoge(&$b)
{
$b *= 10;
}
$a = 2;
hoge($a);
echo $a;
?>
実行結果
20
まとめ
- PHPの参照はメモリのアドレスではなく、参照元の変数のエイリアスとして同じ値を持つ。
- 変数の先頭に「&」をつけることによって参照渡しを行い、参照元の変数の値を共有できる。
- 参照元、参照先どちらかの値を変更すると、もう一方の値も変更される。
- 参照渡しは配列、オブジェクト、関数でも使用することができる。(オブジェクトはデフォルトで参照渡しされている)