【PHP】値渡しと参照渡し - 変数の値または参照を渡す

【PHP】値渡しと参照渡し - 変数の値または参照を渡す

PHPの変数から情報を渡す方法には種類があります。

ここでは、その種類である『値渡し』と『参照渡し』について解説します。

検証環境

値渡し

値渡しは“変数の値を渡す”ことです。

値を渡す側の変数をa、受け取る側の変数をbとしたとき、aとbはそれぞれ異なる記憶領域を持ちます。

そのため、一方の変数の値を変更しても、他方の変数の値に影響しません。

例えば、次のコードは$aの値渡しです。

<?php

$a = 'Hello';

___ih_hl_start
$b = $a;
___ih_hl_end

echo "[a-1] " . $a . "\n";
echo "[b-1] " . $b . "\n";

$b = 'World';

echo "[a-2] " . $a . "\n";
echo "[b-2] " . $b . "\n";

?>
$ php sample.php
[a-1] Hello
[b-1] Hello
[a-2] Hello
[b-2] World

5行目で、$aの値である'Hello'$bに渡しています。

その後、10行目で$bの値を変更していますが、その前後の出力で$aの値は変わりません。

参照渡し

参照渡しは“変数の記憶領域(参照先)を渡す”ことです。

値を渡す側の変数をa、受け取る側の変数をbとしたとき、aとbは同じ記憶領域を持ちます。

そのため、一方の変数の値を変更すると、他方の変数の値も変わります。

例えば上記サンプルを$aの参照渡しに変更すると次のようになります。

<?php

$a = 'Hello';

___ih_diff_start
-$b = $a;
+$b = &$a;
___ih_diff_end

echo "[a-1] " . $a . "\n";
echo "[b-1] " . $b . "\n";

$b = 'World';

echo "[a-2] " . $a . "\n";
echo "[b-2] " . $b . "\n";

?>
$ php sample.php
[a-1] Hello
[b-1] Hello
[a-2] World
[b-2] World

5行目の&$aが参照渡しです。

参照渡しは変数の前にアンパサンド(&)を記述します。

$a$bは同じ記憶領域を持つため、10行目の$bの値の変更に伴って、$aの値も変わったことが実行結果から分かります。

引数の参照渡し

引数に参照渡しを使うことが可能です。

最も一般的な引数は値渡しであり、例えば次のようなコードです。

<?php

function message( $text ) {
    ___ih_hl_start
    $text = 'World';
    ___ih_hl_end
    echo "[text]     " . $text . "\n";
}

$greeting = 'Hello';

message($greeting);

echo "[greeting] " . $greeting ."\n";
 
?>
$ php sample.php
[text]     World
[greeting] Hello

仮引数$text$greetingを実引数として与えています。

4行目で$textの値を変更していますが、値渡しのため、$greetingには影響しません。

この$textに参照渡しするには、仮引数の前にアンパサンドを記述します。

<?php

___ih_diff_start
-function message( $text ) {
+function message( &$text ) {
___ih_diff_end
    $text = 'World';
    echo "[text]     " . $text . "\n";
}

$greeting = 'Hello';

message($greeting);

echo "[greeting] " . $greeting ."\n";
 
?>
$ php sample.php
[text]     World
[greeting] World

このようにすることで実引数($greeting)と仮引数($text)は同じ記憶領域を持ちます。

そのため、関数の処理でも$textの値を変更すると、$greetingの値も変わります。

オブジェクトの参照渡し

オブジェクトは常に参照渡しです。

そのため、アンパサンドを付けなくても参照渡しとして処理されます。

<?php

class Test {
    
    public $field;
    
}

$a = new Test();
$a->field = 'Hello';

___ih_hl_start
$b = $a;
___ih_hl_end

echo "[a-1] " . $a->field ."\n";
echo "[b-1] " . $b->field ."\n";

$b->field = 'World';

echo "[a-2] " . $a->field ."\n";
echo "[b-2] " . $b->field ."\n";

?>
$ php sample.php
[a-1] Hello
[b-1] Hello
[a-2] World
[b-2] World

もし、互いに影響を与えたくない場合はcloneキーワードを使用します。

<?php

class Test {
    
    public $field;
    
}

$a = new Test();
$a->field = 'Hello';

___ih_diff_start
-$b = $a;
+$b = clone $a;
___ih_diff_end

echo "[a-1] " . $a->field ."\n";
echo "[b-1] " . $b->field ."\n";

$b->field = 'World';

echo "[a-2] " . $a->field ."\n";
echo "[b-2] " . $b->field ."\n";

?>
$ php sample.php
[a-1] Hello
[b-1] Hello
[a-2] Hello
[b-2] World

cloneキーワードは、異なる記憶領域にオブジェクトを複製するため、変更の影響を受けません。

また、関数やメソッドなどの仮引数にアンパサンドが付いていない場合も同様です。

<?php

class Test {
    
    public $field;
    
}

function handle( $x ) {
    $x->field = 'World';
    echo '[x] ' . $x->field . "\n";
}

$a = new Test();
$a->field = 'Hello';

___ih_hl_start
handle($a);
___ih_hl_end
echo '[a] ' . $a->field . "\n";

$a->field = 'Hello';

___ih_hl_start
handle(clone $a);
___ih_hl_end
echo '[a] ' . $a->field . "\n";

?>
$ php sample.php
[x] World
[a] World
[x] World
[a] Hello