[PHP] 参照(リファレンス)について
参照(リファレンス)とは、メモリ上のアドレスそのものを代入し、複数の変数を同一のものとして扱うことが出来ます。
ここではPHPのリファレンスについて正しく理解するためにまとめます。
リファレンスの代入
構文
変数の前に「&」を付けると、変数のメモリ上のアドレスであるリファレンスを取得することが出来ます。
&変数
[実装例]リファレンスの代入
コード
以下の例では、変数$aの参照を変数$bに代入し、そのあと変数$bを更新しています。
$a = 1;
$b = &$a;
$b = 2;
var_dump($a, $b);
実行結果
実行すると変数$a、$bどちらも同じように更新されていることが分かります。
$ php test_reference.php int(2) int(2)
[実装例]リファレンスの解除
コード
unset関数でリファレンスの解除が出来ます。
$a = 1;
$b = &$a;
unset($b);
$b = 2;
var_dump($a, $b);
実行結果
$ php test_reference.php int(1) int(2)
参照渡し
関数やメソッドの引数に、変数の参照を渡してやることが出来ます。
[実装例]参照渡し
コード
以下の例では、関数addVarの引数を参照渡しにして、関数内で$varの値を更新しています。
function addVar(int &$var) {
$var++;
}
$var = 1;
addVar($var);
var_dump($var);
実行結果
実行結果は、関数の外で宣言された$varの値が更新されていることが分かります。
$ php test_reference.php int(2)
変数以外を渡すとエラー
参照渡しが設定されている引数に、変数以外の値を直接渡すことはできません。
例えば関数addVarの呼び出しを、
addVar(1);
とすると、以下のエラーが発生します。
$ php test_reference.php Fatal error: Uncaught Error: addVar(): Argument #1 ($var) cannot be passed by reference in .\test_reference.php:16 Stack trace: #0 {main} thrown in .\test_reference.php on line 16
参照返し
クラスのメソッドで返す値を参照に返ることが出来ます。これを参照返しと言います。
構文
参照返しは、メソッドの先頭に「&」を付けることと、呼び出し側でも「&」を付けて呼び出すことで、メソッドの戻り値を参照で受け取ることが出来ます。
function &メソッド名() {
//
}
[実装例]参照返し
以下の例では、メソッドgetVarが参照返しで定義していて、呼び出し側も参照を受け取る呼び出し方をしています。そのため「$var++」の結果が$testオブジェクトの属性$varに及んでいることが分かります。
コード
class Test {
private int $var;
public function __construct(int $var) {
$this->var = $var;
}
public function &getVar() {
return $this->var;
}
}
$test = new Test(1);
$var = &$test->getVar();
$var++;
var_dump($test);
実行結果
$ php test_reference.php object(Test)#1 (1) { ["var":"Test":private]=> &int(2) }
参照返しにならないケース
参照返しで定義されているメソッドを、呼び出し側で「&」なしで、以下のように呼び出した場合
$var = $test->getVar();
この場合はリファレンスを受け取れないので、$testオブジェクトの属性$varの値は変わりません。
$ php test_reference.php object(Test)#1 (1) { ["var":"Test":private]=> int(1) }
エラーになるケース
上記とは逆に、参照返しが設定されていないメソッドを、参照を受け取る方法で呼び出した場合は以下のエラーが発生します。
$ php test_reference.php Notice: Only variables should be assigned by reference in .\test_reference.php on line 37 object(Test)#1 (1) { ["var":"Test":private]=> int(1) }
コメント
コメントを投稿