🐈
phpでの値渡し、参照渡しを理解する
言語による大きな違いはないと思うが、php独自の部分もあるかもしれないのでタイトルはphpでのとつけました。
○○渡しとはどういう時に使う用語?
関数やメソッドに引数の渡し方の種類を表す用語
- 値渡し
- 変数の値をコピーする渡し方
- 参照渡し
- 変数を共有するような渡し方
※変数の実体はメモリ領域にある。
挙動の違い
挙動の確認は
PHP Sandbox のphp8で試した
変数
値渡しでは
参照渡しでは
値渡し
-
bに代入するaの値を - $aの値を変更する
- $bの値は変わらない
<?php
$a = 1;
$b = $a;
$a = $a + 1;
//結果
int(1)
参照渡し
-
bに代入するaの値を - $aの値を変更する
- $bの値も変わる
<?php
$a = 1;
$b =& $a;
$a = $a + 1;
//結果
int(2)
配列
変数の時と同じ。
値渡しでは
-
arrayを代入するnewArrayに - $array[1]の値を変更する
- $newArray[1]の中身が変わらない
参照渡しでは
-
arrayを代入するnewArrayに - $array[1]の値を変更する
- $newArray[1]の中身が変わる
値渡し
<?php
$array = [1, 2, 3];
$newArray = $array;
$array[1] = 0;
var_dump($newArray);
//結果
array(3) {
[0]=>
int(1)
[1]=>
int(2) //変わっていない
[2]=>
int(3)
}
参照渡し
<?php
$array = [1, 2, 3];
$newArray =& $array;
$array[1] = 0;
var_dump($newArray);
//結果
array(3) {
[0]=>
int(1)
[1]=>
int(0) //変わっている
[2]=>
int(3)
}
オブジェクト
phpのオブジェクトは参照型のため、&がなくても参照される。
<php
$carbon = new Carbon();
[]
値渡し
<?php
$stdClass = new stdClass();
$stdClass->property = 1;
$newStdClass = $stdClass;
$stdClass->property = 3;
var_dump($newStdClass);
// 結果
object(stdClass)#1 (1) {
["property"]=>
int(3)
}
参照渡し
参照させたくなければ cloneをつける。
<?php
$stdClass = new stdClass();
$stdClass->property = 1;
$newStdClass = clone $stdClass;
$stdClass->property = 3;
var_dump($newStdClass);
// 結果
object(stdClass)#2 (1) {
["property"]=>
int(1)
}
自分はこの挙動がわかっていなくて詰まった経験がある。
例えば日付の配列を作るときに次のように実装したが、日付が同じになって戸惑った経験があるw
<?php
$dateTime = new \DateTime();
$dateArray = [
$dateTime,//今日
$dateTime->modify('+1 days'), //明日
$dateTime->modify('+2 days'),//明後日
];
var_dump($dateArray);
//期待する結果
array(3) {
[0]=>
object(DateTime)#1 (3) {
["date"]=>
string(26) "2021-05-26 16:35:19.007567"
["timezone_type"]=>
int(3)
["timezone"]=>
string(10) "US/Pacific"
}
[1]=>
object(DateTime)#1 (3) {
["date"]=>
string(26) "2021-05-27 16:35:19.007567"
["timezone_type"]=>
int(3)
["timezone"]=>
string(10) "US/Pacific"
}
[2]=>
object(DateTime)#1 (3) {
["date"]=>
string(26) "2021-05-28 16:35:19.007567"
["timezone_type"]=>
int(3)
["timezone"]=>
string(10) "US/Pacific"
}
}
//実際の結果は全て同じ日付になっている
array(3) {
[0]=>
object(DateTime)#1 (3) {
["date"]=>
string(26) "2021-05-28 16:35:19.007567"
["timezone_type"]=>
int(3)
["timezone"]=>
string(10) "US/Pacific"
}
[1]=>
object(DateTime)#1 (3) {
["date"]=>
string(26) "2021-05-28 16:35:19.007567"
["timezone_type"]=>
int(3)
["timezone"]=>
string(10) "US/Pacific"
}
[2]=>
object(DateTime)#1 (3) {
["date"]=>
string(26) "2021-05-28 16:35:19.007567"
["timezone_type"]=>
int(3)
["timezone"]=>
string(10) "US/Pacific"
}
}
どう使い分ける?
挙動としては理解できた!
参照渡しを使うメリットがパフォーマンスが向上するくらいしか把握できていない。
値渡しだと変数から別の変数に値をコピーするため、メモリ上に新たにデータが追加される。
参照渡しでは別の変数に入ってはいるが、メモリ上使っているところは同じと理解している。
参照渡しを使う事はあまりないけど、オブジェクトがどういう挙動をするかという意味では勉強になった😇
Discussion
とありますが、これは参照渡しではないので注意が必要です。