PHPでのリファレンスの代入についてまとめました

19/05/12 23:43:46     19/06/02 13:15:43

PHPでのリファレンスの代入についてまとめました

プログラミング言語においてはリファレンス、参照、参照渡し、値渡し、などの概念があります。そしてそれはPHPでも同じです。

これらの概念は基本的にどのプログラミング言語でも同じなのですが、具体的にどのようなコードを記述したら参照になるのか値になるのか、といった点は言語によってまちまちです。

そこでこのページでは、そもそもリファレンス、参照、参照渡し、値渡しの概念の意味は?PHPではどのように記述する?といったことを解説していきます。

リファレンス、参照、参照渡し、値渡し、リファレンスの代入などの意味

まずリファレンス、参照、参照渡し、値渡し、リファレンスの代入などの用語の意味についてですが、リファレンスと参照は基本的に同じ意味になります。違いがよくわからないという声もあるようですが、英語か日本語かの違いです。

そして参照渡し、値渡しが対比されることが多いですが、要素を渡す方法にはこの二種類があります。この二種類の対比については後で説明します。リファレンスの代入については、参照渡しと同じ意味です。

たとえば変数から変数に要素を渡す際に、リファレンスの代入だと参照先のアドレスを渡すことになります。

参照渡しとは

参照渡しとは、渡したい要素に直接アクセスするための場所を渡す方法です。情報処理の勉強をされたことのある方はピンとくるかもしれませんが、プログラミングで扱う要素はすべてメモリ上のどこかに格納されています。

そして、参照渡しでは「メモリのここにアクセスしたら要素がありますよ」と参照値を渡しています。サンプルコードで確認すると、以下のようになります。

<?php
function hoge(&$foo)
{
    $foo = null;
}
$piyo = 1;
hoge($piyo);
var_dump($piyo);
?>

上記のコードを実行すると、「NULL」と出力されます。ここで重要なポイントは、hoge関数の中で書き換えた値が関数外にも影響が出ているということです。$piyo = 1で1を設定した後にhoge関数を呼び出して値を書き換えていて、最終的に出力した結果で関数で置き換えた値になっています。

参照渡しの場合メモリ領域で直接値を参照するので、それを書き換えると元の値が変わります。参照渡しにする場合、&$fooのように変数名の前に「&」を付けます。

値渡しとは

次に値渡しとは、値をコピーして渡す方法です。言葉のイメージ的に値渡しの方が直接値を渡したり書き換えたりしそうなイメージですが、値渡しはあくまでもメモリ領域の別の場所に値をコピーする方法で、直接元の値に影響を及ぼしません。

参照渡しは直接値を参照する、値渡しは間接的に値を渡す、ということです。初めて聞くとややこしいかもしれませんが、すぐに慣れるかと思います。値渡しのサンプルコードは以下です。

<?php
function hoge($foo)
{
    $foo = null;
}
$piyo = 1;
hoge($piyo);
var_dump($piyo);
?>

上記のコードを実行すると、「int(1)」と出力されます。$piyo = 1で1をセットした後にhoge関数を実行してnullを入れていますが、最終的な出力結果ではhoge関数の影響を受けていません。

これはhoge関数の引数が$fooとなっており、&が付いていないからです。&が付いていないと値渡しになるので、メモリ上は別の場所に新たに値をコピーしています。

コピーした値を書き換えるだけなので、元の値には何の影響も与えません。値渡しと参照渡しを知らない、もしくは特別意識せずにコードを書いている場合、&は付けずに書いているはずなので結果的に値渡しになっています。

意図しないバグを防ぐためには値渡しにしておいた方が別の場所の値を書き換えない分リスクが少ないのですが、場合によっては関数で関数外の変数に影響を与えたいこともあるかと思います。

その場合参照渡しを使うことになるので、値渡しと参照渡しは違いを理解したうえでコードを書いた方が良いです。

参照渡しの練習

参照渡しは上で説明した通り「&」を付けるだけなので特別難しいことはないのですが、実際にコーディングしているとどうしても混乱することがあったり、細かい記述がよくわからなかったりするかもしれません。

そこで、よくあるコーディングパターンで参照渡しを紹介しておきます。まずは配列を参照渡しして関数の中で処理するパターンです。

<?php
function hoge(&$foo)
{
    $foo[2] = 1;
    array_pop($foo);
}
$piyo = [1, 2, 3, 4];
hoge($piyo);
var_dump($piyo);
?>

上記のコードを実行すると、以下のように出力されます。

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

参照渡しで関数に配列を渡し、関数の中では配列の2番目に1を格納し、次にarray_pop関数で配列の末尾を削除しています。その結果、配列の2番目の要素が1に変わり、配列の末尾も消えました。

ちなみに配列の要素は1からでなく0から数えるので、2番目は1から数えた場合の3番目になります。次にオブジェクトを参照渡しで渡す例です。

<?php
class Hoge {
    protected $piyo = 1;
    public function setValue($value) {
        $this->piyo = $value;
    }
    public function getValue() {
        return $this->piyo;
    }
}
function foo(&$qux)
{
    $qux->setValue(5);
}
$object = new Hoge();
foo($object);
echo $object->getValue();
?>

上記のコードを実行すると、「5」と出力されます。処理の流れとしてはまずHogeクラスを定義しています。クラスの中ではsetValueメソッドとgetValueメソッドが定義されています。

次にfoo関数を定義します。foo関数はsetValueメソッドを呼び出して5をセットするための関数です。次にHogeクラスのオブジェクトを生成します。そのオブジェクトを引数にする形でfoo関数を呼び出し、foo関数の中でsetValueで5をセットしました。

最後にgetValueでセットした値を取得して出力しています。このように一つ一つの処理を追っていくと、一見複雑に見えなくもないソースコードがトレースできます。

一つ一つのコードの詳細がいまいちわからないということがもしかするとあるかもしれませんが、今回は処理の大枠が理解でき、その結果参照渡しがどのように使われているのかわかればそれで問題ありません。

大枠さえ理解できれば、実際にコーディングする際の詳細はその都度調べれば実装できます。プログラミングにおいては大枠の設計を考えることがもっとも重要です。

まとめ

以上、リファレンスの代入、参照渡し、値渡しといった概念とその使い方について解説してきました。

基本的な部分なのであまり面白みはないかもしれませんが、機能性の高いシステムを作るためにはこのような基礎の部分が重要です。

すべてのシステムは基礎の積み重ねでしかないので、ぜひこういった基本概念をきっちり押さえていってください。

人気記事

編集部おすすめ記事

この記事を読んだ人はこんな記事を読んでいます

案件探しやフリーランスになるための相談する