[PHP] 非オブジェクト指向の「変数の参照」
【2012.05.01 追記】foreachでの利用
PHPの非オブジェクト指向における参照(リファレンス)とは、あくまで「変数の参照」。
つまり、変数の別名(エイリアス)をつくっているにすぎない。
C/C++のポインタなどとは根本的に異なり、値やオブジェクトの参照(メモリのアドレス)をとっているわけではないことに注意。
$a = 5; $b = &$a; echo $b; // 5 $a = new stdClass; echo is_object($b); // 1 // 数値の5でないということは、値やオブジェクトの参照を // とっていないということ
関数の引数に変数の参照をとる
この場合も、引数を特定の変数のエイリアスにしているのと同じ(1)。
function test(&$param = 5) { echo $param; $param = 10; } $a = 1; test($a); // 1---(1) echo $a; // 10 test(); // 5---(2)
その引数にデフォルト値を設定できる(2)。
あくまでエイリアスをつくっているのだから、そもそも実引数を指定しない(エイリアスの元がない)のはおかしいと思うのだが、PHPではこの場合、参照をとる仮引数(エイリアスとなるはずだった引数)を通常の引数として扱う。
変数の参照(エイリアス)を返す関数
function & doFunction() { static $local = 1; echo $local; return $local; } class Sample { private $prop = 1; public function & doSample() { echo $this->prop; return $this->prop; } public function echoProp() { echo $this->prop; } } $outerLoacl = &doFunction(); // 1 ++$outerLoacl; doFunction(); // 2 $sample = new Sample; $outerProp = &$sample->doSample(); // 1 ++$outerProp; $sample->echoProp(); // 2
関数の側でも、受ける変数(エイリアス)の側でも「&」を指定する必要がある(そうしないと、通常の代入になる)。
関数内の静的変数も、クラスのprivateなプロパティもエイリアスをつくれてしまう。
柔軟性が高いが、リスクも高いので使う場面に気をつけたほうがいい。
foreachでの利用
使い方としては単純。(1)
$arr1 = array(0, 1, 2); foreach ($arr1 as &$value) { // (1) ++$value; } $arr2 = array(10, 11, 12); foreach ($arr2 as $value) { // (2) ++$value; } echo $arr1[2]; // 10 (3)
(2)で$valueを使い回してしまうと、前のforeachのarr1[2]の変数の参照(エイリアス)が残っているため、(2)でそのエイリアスに$arr2[0]の値が代入されて、(3)のような結果になる。
これを防ぐには、unset($value)すればいいのだが、それ以前にローカル変数の使い回しをやめるべきだろう。
(PHPは関数単位のスコープしかない)