[PHP] 初心者的リファレンス(参照) の理解

PHPのリファレンス(参照) を勉強したメモ書き。

を参考にした。

とりあえずカンタンなコード

<?php
$a = "a";
$b = "HOGEHOGE";
$b =& $a;
$a = "c";
echo "a is $a.\n";
echo "b is $b.\n";
unset($a);
echo "a is $a.\n";
echo "b is $b.";
?>

結果

a is c.
b is c.
a is .
b is c.

$a を unset しても参照先の値が消えるわけではないので、 最後の $b は "c" が出力される。

スコープと参照1

<?php
$var1 = "VAR1" ;
$var2 = "VAR2" ;
function reference_test()
{
  global $var1, $var2 ;
  $var2 =& $var1; // 関数の内部でのみ参照可能
  echo "関数内の\$var2の値は $var2 \n";
}

reference_test();
echo "関数外の\$var2の値は $var2";

?>

結果

関数内の$var2の値は VAR1
関数外の$var2の値は VAR2

PHPマニュアルによると

「global $var; は、$var =& $GLOBALS['var']; の短縮版だと考えて」

とある。つまり global宣言した変数はグローバル変数そのまま使っているわけではなく、 ローカル変数 $var に グローバル変数 $var の参照が渡されているだけ。 だから関数を抜けたらローカル変数は消えてなくなるだけでグローバル変数の参照は変化しない。

スコープと参照2

<?php
$var1 = "VAR1" ;
$var2 = "VAR2" ;
function reference_test()
{
  global $var1, $var2 ;
  $var2 =& $var1;
  $var2 = "HOGEHOGE";
}

reference_test();

echo "$var1\n";
echo "$var2";

?>

結果

HOGEHOGE
VAR2

関数内の $var2 =& $var1 により ローカル変数$var2 の参照は グローバル変数$var1 の参照に変わる。 したがって $var2 =& $var1 により グローバル変数$var2 と同じ参照を持つローカル変数がなくなるので、グローバル変数$var2の参照先の値を変えることはできなくなる。だから$var2 = "HOGEHOGE" しても グローバルスコープの$var1の参照先の値が変わるだけ。

スコープと参照3

<?php
$var1 = "VAR1" ;
$var2 = "VAR2" ;
$var3 = "VAR3" ;
function reference_test()
{
  global $var1, $var2 ;
  $var3 =& $GLOBALS['var3'] ;
  echo "$var1 $var2 $var3\n";

  $GLOBALS['var2'] =& $var1 ;
  $GLOBALS['var3'] =& $var1 ;
}

reference_test();
echo "$var1 $var2 $var3\n";

?>

結果

VAR1 VAR2 VAR3
VAR1 VAR1 VAR1

$GLOBALS['var']に参照を渡してやれば関数外部で使える。

配列に渡した参照

<?php
$arr = array(1); // $arr[0] == 1 ;
$hoge =& $arr[0] ;
$foo = $arr ;
var_dump($foo) ;

$foo[0] += 101 ;
echo "\n//さて $arr の中身はいかに?\n";
var_dump($arr) ;

?>

結果

array(1) {
  [0]=>
  &int(1)
}

//さて $arr の中身はいかに?
array(1) {
  [0]=>
  &int(102)
}

配列に参照を入れると & を使っていないのに参照が渡されてしまうので注意。…ってかなんだかよくわからん。is_ref フラグが立ってると配列の中身は参照で受け渡しされるってこと??このあたりは誤解してそうだ…[PDF] http://www.derickrethans.nl/files/php-secrets-forum7.pdf をきちんと理解したい

リファレンス渡し

<?php

function ref_test( &$var )
{
  $var = "REF_TEST!!";
}

ref_test( $hoge );
echo $hoge ;

?>

結果

REF_TEST!!

まあこれは特に難しくもない。。

リファレンス返し

  • 関数の名前の前に & を付加することにより関数がリファレンスを返すようになる。
  • 関数が返したリファレンスを受け取る場合にも & を使う。 $var =& func();
  • 関数内で配列に参照を入れて返すと…!?

    <?php
    
    $foo = 2 ;
    $bar = 5 ;
    
    function & ref_foo()
    {
    global $foo ;
    return $foo ;
    }
    
    function ref_bar()
    {
    global $bar ;
    return array( &$bar ) ;
    }
    
    $ref_foo =& ref_foo();
    $ref_bar =  ref_bar();
    
    echo "$ref_foo, $ref_bar[0]", "\n";
    
    $foo = "na" ;
    $bar = "nanndatte-" ;
    
    echo "$ref_foo, $ref_bar[0]";
    
    ?>
    

結果

2, 5
na, nanndatte-

これは…?

<?php
function &ref_test( &$var1, $var2 )
{
  $var1 = "????" ;
  global $$var2 ;
  return $$var2 ;
}
$hoge = "HOGE" ;
$foo = &ref_test( $bar, "hoge" );
echo "$foo, $bar, $hoge", "\n";

$foo = "FOO?";
echo "$foo, $bar, $hoge" ;
?>

結果

HOGE, ????, HOGE
FOO?, ????, FOO?

無意味な合体。

メモ

実行速度を向上させるためにリファレンスは使うときは要注意。 バグの元だし、場合によっては余計なリソースを消費する結果に。 つまりあんまり理解せずにやっても意味ないよ、と。

以下のリンクはもっと参照を理解するために…と、読んだけどいまいち理解できなかった orz

またしばらく勉強したあとに読もう…

Share
関連記事