PHPでは、次のように、関数宣言のパラメーターの前にアンパサンドを付加することにより、参照によって関数パラメーターを渡すことができます。
function foo(&$bar)
{
// ...
}
今、私はこれが ない パフォーマンスを改善するように設計されていますが、通常はスコープ外の変数を関数が変更できるようにします。
代わりに、PHPはオブジェクトが変更されるまでオブジェクト(およびおそらく配列も)のコピーを回避するためにコピーオンライトを使用しているようです。そのため、パラメーターを変更しない関数の場合、効果は同じです。参照によってそれらを渡したかのように。
しかし、コピーオンライトロジックが参照渡しで短絡している可能性があるかどうか、およびパフォーマンスに影響があるかどうかを考えていました。
ETA:確かに、私はそれがより速くないと思います、そして私はこれが参照がそうであるものではないことをよく知っています。だから私は自分の推測はかなり良いと思います。私は、実際に何が起こっているのかを本当に知っている人からの答えを探しています。 PHP開発の5年間、私は常にPHP内部のソースを読むことから内部情報が不足しているため、品質情報を取得するのが難しいことに気づきました。
20 kBの文字列で関数を呼び出す10万回のテストの結果は次のとおりです。
pass by value: 0.12065005 seconds
pass by reference: 1.52171397 seconds
pass by value: 1.52223396 seconds
pass by reference: 1.52388787 seconds
値でパラメーターを渡す方が常に高速です
関数が渡された変数の値を変更する場合、実用上、値よりも参照渡しと同じです。
与えられた答えがわからなかったので、これについていくつかのテストを実行しました。
私の結果は、参照により大きな配列または文字列を渡すIS大幅に高速であることを示しています。
これが私の結果です:
Y軸(実行)は、1秒間に関数を呼び出すことができる回数です* 10
テストは、関数/変数ごとに8回繰り返されました。
そしてここに私が使用した変数があります:
$large_array = array_fill(PHP_INT_MAX / 2, 1000, 'a');
$small_array = array('this', 'is', 'a', 'small', 'array');
$large_object = (object)$large_array;
$large_string = str_repeat('a', 100000);
$small_string = 'this is a small string';
$value = PHP_INT_MAX / 2;
これらは機能です:
function pass_by_ref(&$var) {
}
function pass_by_val($var) {
}
10kバイトの文字列の値と参照を2つの同一の関数に渡して実験しました。 1つは値で引数を取り、もう1つは参照で引数をとります。それらは一般的な関数でした-引数を取り、単純な処理を行い、値を返します。私は両方で10万回の呼び出しを行い、参照がパフォーマンスを向上させるように設計されていないことを理解しました-参照の利益は4〜5%近くで、文字列が十分に大きくなったときにのみ成長します(100k以上、6〜7%の改善をもたらした) 。したがって、私の結論はパフォーマンスを向上させるために参照を使用しないでください。これはそのためのものではありません。
私が使用したPHPバージョン5.3.1
いいえ、それは速くはないと確信しています。さらに、このマニュアルでは、リファレンスを使用してパフォーマンスを向上させないようにと具体的に述べています。
編集:それが言うところを見つけることができませんが、そこにあります!
コードのテスト片に勝るものはありません
<?PHP
$r = array();
for($i=0; $i<500;$i++){
$r[]=5;
}
function a($r){
$r[0]=1;
}
function b(&$r){
$r[0]=1;
}
$start = microtime(true);
for($i=0;$i<9999;$i++){
//a($r);
b($r);
}
$end = microtime(true);
echo $end-$start;
?>
最終結果!配列が大きいほど(または呼び出し回数が多いほど)、差は大きくなります。したがって、この場合、値は関数内で変更されるため、参照による呼び出しの方が高速です。
それ以外の場合、「参照」と「値」の間に実際の違いはありません。コンパイラーは、必要がない場合に毎回新しいコピーを作成しないように十分にスマートです。
シンプルで、何もテストする必要はありません。ユースケースによって異なります。
値による受け渡しは、少量の引数の参照よりも常に速い値で行われます。これは、アーキテクチャーがレジスター(ABI)を介して渡すことができる変数の数によって異なります。
たとえば、x64では、64ビットの4つの値をレジスタに渡すことができます。 https://en.wikipedia.org/wiki/X86_calling_conventions
これは、ポインターを逆参照する必要がないため、値を直接使用するだけです。
渡される必要のあるデータがABIよりも大きい場合、残りの値はスタックされます。この場合、配列またはオブジェクト(インスタンスはクラス、または構造+ヘッダー)は常に参照により高速になります。
これは、参照がデータへのポインタ(データ自体ではなく)であり、固定サイズ、たとえばマシンに応じて32ビットまたは64ビットであるためです。そのポインタは1つのCPUレジスタに収まります。
PHPはC/C++で書かれているので、同じように動作すると思います。
私が取り組んでいるプロジェクトに基づいた実際の例でこれをベンチマークしようとしました。いつものように、違いは取るに足らないものですが、結果はやや予想外でした。私が見たほとんどのベンチマークでは、呼び出された関数は渡された値を実際には変更しません。単純なstr_replace()を実行しました。
**Pass by Value Test Code:**
$originalString=''; // 1000 pseudo-random digits
function replace($string) {
return str_replace('1', 'x',$string);
}
$output = '';
/* set start time */
$mtime = microtime();
$mtime = explode(" ", $mtime);
$mtime = $mtime[1] + $mtime[0];
$tstart = $mtime;
set_time_limit(0);
for ($i = 0; $i < 10; $i++ ) {
for ($j = 0; $j < 1000000; $j++) {
$string = $originalString;
$string = replace($string);
}
}
/* report how long it took */
$mtime = microtime();
$mtime = explode(" ", $mtime);
$mtime = $mtime[1] + $mtime[0];
$tend = $mtime;
$totalTime = ($tend - $tstart);
$totalTime = sprintf("%2.4f s", $totalTime);
$output .= "\n" . 'Total Time' .
': ' . $totalTime;
$output .= "\n" . $string;
echo $output;
参照テストコードで渡す
以外は同じ
function replace(&$string) {
$string = str_replace('1', 'x',$string);
}
/* ... */
replace($string);
秒単位の結果(1000万回反復):
PHP 5
Value: 14.1007
Reference: 11.5564
PHP 7
Value: 3.0799
Reference: 2.9489
違いは関数呼び出しごとのミリ秒のほんの一部ですが、この使用例では、参照渡しはPHP 5とPHP 7。
(注:PHP 7のテストはより高速なマシンで実行されました-PHP 7はより高速ですが、おそらくそれほど高速ではありません。)