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