web-dev-qa-db-ja.com

PHP(> = 5.0))では、参照渡しの方が速いですか?

PHPでは、次のように、関数宣言のパラメーターの前にアンパサンドを付加することにより、参照によって関数パラメーターを渡すことができます。

function foo(&$bar)
{
    // ...
}

今、私はこれが ない パフォーマンスを改善するように設計されていますが、通常はスコープ外の変数を関数が変更できるようにします。

代わりに、PHPはオブジェクトが変更されるまでオブジェクト(およびおそらく配列も)のコピーを回避するためにコピーオンライトを使用しているようです。そのため、パラメーターを変更しない関数の場合、効果は同じです。参照によってそれらを渡したかのように。

しかし、コピーオンライトロジックが参照渡しで短絡している可能性があるかどうか、およびパフォーマンスに影響があるかどうかを考えていました。

ETA:確かに、私はそれがより速くないと思います、そして私はこれが参照がそうであるものではないことをよく知っています。だから私は自分の推測はかなり良いと思います。私は、実際に何が起こっているのかを本当に知っている人からの答えを探しています。 PHP開発の5年間、私は常にPHP内部のソースを読むことから内部情報が不足しているため、品質情報を取得するのが難しいことに気づきました。

63
Hanno Fietz

Zend Engineはコピーオンライトを使用します。自分で参照を使用すると、少し余分なオーバーヘッドが発生します。ただし、執筆時点では この言及 のみを検索でき、 マニュアル のコメントには他のリンクが含まれています。

(編集) オブジェクトと参照 のマニュアルページには、オブジェクト変数が参照とどのように異なるかについての情報が少し含まれています。

33
Paul Dixon

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

結論

  1. 値でパラメーターを渡す方が常に高速です

  2. 関数が渡された変数の値を変更する場合、実用上、値よりも参照渡しと同じです。

71
ikary

与えられた答えがわからなかったので、これについていくつかのテストを実行しました。

私の結果は、参照により大きな配列または文字列を渡すIS大幅に高速であることを示しています。

これが私の結果です: Benchmark

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) {
}
27
Petah

10kバイトの文字列の値と参照を2つの同一の関数に渡して実験しました。 1つは値で引数を取り、もう1つは参照で引数をとります。それらは一般的な関数でした-引数を取り、単純な処理を行い、値を返します。私は両方で10万回の呼び出しを行い、参照がパフォーマンスを向上させるように設計されていないことを理解しました-参照の利益は4〜5%近くで、文字列が十分に大きくなったときにのみ成長します(100k以上、6〜7%の改善をもたらした) 。したがって、私の結論はパフォーマンスを向上させるために参照を使用しないでください。これはそのためのものではありません。

私が使用したPHPバージョン5.3.1

6
Vladimir Fesko

いいえ、それは速くはないと確信しています。さらに、このマニュアルでは、リファレンスを使用してパフォーマンスを向上させないようにと具体的に述べています。

編集:それが言うところを見つけることができませんが、そこにあります!

4
Greg

コードのテスト片に勝るものはありません

<?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;
?>

最終結果!配列が大きいほど(または呼び出し回数が多いほど)、差は大きくなります。したがって、この場合、値は関数内で変更されるため、参照による呼び出しの方が高速です。

それ以外の場合、「参照」と「値」の間に実際の違いはありません。コンパイラーは、必要がない場合に毎回新しいコピーを作成しないように十分にスマートです。

1
Melsi

シンプルで、何もテストする必要はありません。ユースケースによって異なります。

値による受け渡しは、少量の引数の参照よりも常に速い値で行われます。これは、アーキテクチャーがレジスター(ABI)を介して渡すことができる変数の数によって異なります。

たとえば、x64では、64ビットの4つの値をレジスタに渡すことができます。 https://en.wikipedia.org/wiki/X86_calling_conventions

これは、ポインターを逆参照する必要がないため、値を直接使用するだけです。

渡される必要のあるデータがABIよりも大きい場合、残りの値はスタックされます。この場合、配列またはオブジェクト(インスタンスはクラス、または構造+ヘッダー)は常に参照により高速になります。

これは、参照がデータへのポインタ(データ自体ではなく)であり、固定サイズ、たとえばマシンに応じて32ビットまたは64ビットであるためです。そのポインタは1つのCPUレジスタに収まります。

PHPはC/C++で書かれているので、同じように動作すると思います。

0
orfruit

私が取り組んでいるプロジェクトに基づいた実際の例でこれをベンチマークしようとしました。いつものように、違いは取るに足らないものですが、結果はやや予想外でした。私が見たほとんどのベンチマークでは、呼び出された関数は渡された値を実際には変更しません。単純な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はより高速ですが、おそらくそれほど高速ではありません。)

0
Bob Ray