関数の値渡しと参照渡しどちらが速い?
C言語では、値渡しの場合は値のコピーが渡され、参照渡しの場合は値のアドレスが渡される。単純に考えて参照渡しの方が高速そうですが PHPはどうなのか? これまた確かめてみないと納得できない性格なのでやっちゃいました。
リファレンス == 実体の別名
2004-02-25: PHPの場合、C語と異なり、参照渡し・値渡しの違いは、値が変更された時に初めて起こることが、PaKa様のご指摘によりわかりました。ありがとうございました。
関数に渡した時点ではどちらも「実体」を示す「ポインタのようなもの」が渡されていて、関数内で変更された時はじめて渡した値がコピーされるという動作のようです。つまり受け取った変数を変更しなければ値渡しと参照渡しで差は無いということです。
PHP では「 参照 」と「 リファレンス 」どちらの言葉も使いますが、C語におけるポインタやアドレス渡しを指す参照とは違い、PHP の参照は 「 実体の別名 」 と考えるべき物のようです。混乱を避ける意味で「参照」よりも「リファレンス」というキーワードを使うべきかもしれません。
この差を確かめるべく、関数内で値を変更するようテストコードを直しましたので「新テストコード」をおためしください。
旧テストコード
こちらはこれまで掲載していたテストコードです。以下のコードを実行すると、参照渡しのほうが50%~60%も速い結果が得られますが、はじめに実行した関数の実行時間に何らかのオーバヘッドが含まれている為のようです。(原因は不明) 試しに実行速度の測定部分(赤いところ)を繰り返すと実行速度の差はなくなります。これまで間違った情報を掲載しておりました。申し訳ございませんでした。m(_ _)m
<?php
// 測定用の文字列(1024バイト)
$str = "abcdefg ・・・途中省略・・・56789";
$timeA; // 値渡しの実行時間
$timeS; // 参照渡しの実行時間
$ritu; // 参照渡し/値渡しの割合
$count = 1; // 繰り返す回数
// 現在の時間をマイクロ秒単位で返す関数
function getmicrotime(){
list($msec, $sec) = explode(" ", microtime());
return ((float)$sec + (float)$msec);
}
// 値を受け取る関数
function str1($s) {
//何もしない
}
// 参照を受け取る関数
function str2(&$s) {
//何もしない
}
// 値渡しの実行時間測定
$timeA = getmicrotime();
for($n = 0; $n < $coumt; $n++){
str1($str);
}
$timeA = getmicrotime() - $timeA;
// 参照渡しの実行時間測定
$timeS = getmicrotime();
for($n = 0; $n < $coumt; $n++){
str2($str);
}
$timeS = getmicrotime() - $timeS;
// 値渡しと参照渡しの割合
$ritu = ($timeS / $timeA) * 100;
// 見栄え良くテーブルに出力
print <<<HTML
<html>
<head>
<meta http-equiv=\"content-type\" content=\"text/html;charset=Shift_JIS\">
<title>値渡しと参照渡し、実行速度比較</title>
</head>
<body>
<table border=\"2\">
<caption>値渡しと参照渡し<br> $count 回の実行速度比較</caption>
<tr>
<td>値渡し</td>
<td> $timeA </td>
</tr>
<tr>
<td>参照渡し</td>
<td> $timeS </td>
</tr>
<tr>
<td>参照渡し/値渡し</td>
<td> $ritu (%)</td>
</tr>
</table>
</body>
</html>
HTML;
?>
新テストコード
<?php
// 測定用の文字列(1024バイト)
$str = "abcdefg ・・・途中省略・・・56789";
$timeA; // 値渡しの実行時間
$timeS; // 参照渡しの実行時間
$ritu; // 参照渡し/値渡しの割合
$count = 1; // 繰り返す回数
// 現在の時間をマイクロ秒単位で返す関数
function getmicrotime(){
list($msec, $sec) = explode(" ", microtime());
return ((float)$sec + (float)$msec);
}
// 値を受け取る関数
function str1($s) {
$s .= "ABCDE";
}
// 参照を受け取る関数
function str2(&$s) {
$s .= "ABCDE";
}
// 値渡しの実行時間測定
$timeA = getmicrotime();
for($n = 0; $n < $coumt; $n++){
str1($str);
}
$timeA = getmicrotime() - $timeA;
// 参照渡しの実行時間測定
$timeS = getmicrotime();
for($n = 0; $n < $coumt; $n++){
str2($str);
}
$timeS = getmicrotime() - $timeS;
// (何らかの)オーバーヘッドをクリアする為もう1回実行
// 値渡しの実行時間測定
$timeA = getmicrotime();
for($n = 0; $n < $coumt; $n++){
str1($str);
}
$timeA = getmicrotime() - $timeA;
// 参照渡しの実行時間測定
$timeS = getmicrotime();
for($n = 0; $n < $coumt; $n++){
str2($str);
}
$timeS = getmicrotime() - $timeS;
// 値渡しと参照渡しの割合
$ritu = ($timeS / $timeA) * 100;
// 見栄え良くテーブルに出力
print <<<HTML
<html>
<head>
<meta http-equiv=\"content-type\" content=\"text/html;charset=Shift_JIS\">
<title>値渡しと参照渡し、実行速度比較</title>
</head>
<body>
<table border=\"2\">
<caption>値渡しと参照渡し<br> $count 回の実行速度比較</caption>
<tr>
<td>値渡し</td>
<td> $timeA </td>
</tr>
<tr>
<td>参照渡し</td>
<td> $timeS </td>
</tr>
<tr>
<td>参照渡し/値渡し</td>
<td> $ritu (%)</td>
</tr>
</table>
</body>
</html>
HTML;
?>
結果
- 新テストコードを実行 (クリックで別ウィンドが開きます)
新テストコードでは リファレンス(参照)渡しの方が 10% ほど高速という結果でした。
それにしても、PHPのリファレンスがC言語のポインタやアドレス渡しとは違うものだということが、この実験最大の収穫でした。


