PHPの関数では通常、引数は値渡し(pass by value)で受け取ります。つまり、関数に渡された値のコピーが関数内で使われ、元の変数には影響しません。しかし、参照渡し(pass by reference)を使うと、関数内で引数の値を変更した場合、呼び出し元の変数も直接変更されます。
参照渡しは、関数から複数の値を返したい場合や、大きなデータ構造を効率的に処理したい場合に使われるテクニックです。
基本的な使い方
引数名の前に &(アンパサンド)を付けることで、その引数を参照渡しにできます。
<?php
function addTen(&$value) {
$value += 10;
}
$num = 5;
echo "変更前: " . $num . "\n";
addTen($num);
echo "変更後: " . $num . "\n";
変更前: 5
変更後: 15
addTen() 関数の引数に & を付けているため、関数内で $value を変更すると、呼び出し元の $num も直接変更されます。もし & を付けなければ、$num は 5 のままです。
値渡しとの比較
違いを明確にするため、値渡しと参照渡しを並べて比較してみましょう。
<?php
// 値渡し(コピーが渡される)
function doubleByValue($x) {
$x *= 2;
echo "関数内: " . $x . "\n";
}
// 参照渡し(元の変数を直接操作)
function doubleByRef(&$x) {
$x *= 2;
echo "関数内: " . $x . "\n";
}
$a = 10;
doubleByValue($a);
echo "呼び出し後(値渡し): " . $a . "\n";
$b = 10;
doubleByRef($b);
echo "呼び出し後(参照渡し): " . $b . "\n";
関数内: 20
呼び出し後(値渡し): 10
関数内: 20
呼び出し後(参照渡し): 20
値渡しでは関数内の変更が元の変数に反映されませんが、参照渡しでは元の変数 $b 自体が 20 に変わっていることがわかります。
配列を参照渡しで操作する
配列に対して参照渡しを使うと、関数内で配列の要素を直接追加・変更できます。
<?php
function addItem(&$cart, $item, $price) {
$cart[] = ["item" => $item, "price" => $price];
}
function calcTotal($cart) {
$total = 0;
foreach ($cart as $entry) {
$total += $entry["price"];
}
return $total;
}
$cart = [];
addItem($cart, "りんご", 150);
addItem($cart, "バナナ", 200);
addItem($cart, "みかん", 100);
foreach ($cart as $entry) {
echo $entry["item"] . ": " . $entry["price"] . "円\n";
}
echo "合計: " . calcTotal($cart) . "円\n";
りんご: 150円
バナナ: 200円
みかん: 100円
合計: 450円
実用的な例
PHPの組み込み関数にも参照渡しを使うものが多数あります。例えば sort() は配列を参照渡しで受け取り、元の配列自体を並べ替えます。
<?php
// エラー情報を参照渡しで取得するパターン
function divide($a, $b, &$error) {
if ($b == 0) {
$error = "ゼロで割ることはできません";
return false;
}
$error = null;
return $a / $b;
}
$error = null;
$result = divide(10, 3, $error);
echo "10 / 3 = " . $result . "(エラー: " . ($error ?? "なし") . ")\n";
$result = divide(10, 0, $error);
echo "10 / 0 = " . var_export($result, true) . "(エラー: " . ($error ?? "なし") . ")\n";
10 / 3 = 3.3333333333333(エラー: なし)
10 / 0 = false(エラー: ゼロで割ることはできません)
参照渡しの引数にはリテラル値を直接渡すことはできません。addTen(5) のような呼び出しはエラーになります。必ず変数を渡してください。また、参照渡しを多用するとコードの追跡が難しくなるため、本当に必要な場面でのみ使用することを推奨します。
PHP 5以降、オブジェクトは常に参照のように振る舞います(正確にはオブジェクトハンドルの値渡し)。そのため、オブジェクトを関数に渡すとき、明示的に & を付けなくても、関数内でのプロパティ変更は元のオブジェクトに反映されます。
まとめ
- 引数名の前に
&を付けると参照渡しになる - 参照渡しでは関数内の変更が呼び出し元の変数に直接反映される
- 値渡しでは変数のコピーが渡されるため、元の変数は変更されない
- 配列の操作やエラー情報の取得など、実用的な場面で活用できる
- リテラル値は参照渡しに渡せない。多用はコードの可読性を下げるので注意