Edited at

PHPの参照渡しは本当に遅い?

More than 5 years have passed since last update.

PHPが糞言語なのはどう考えても参照をポインタだと思っているお前らが悪い

http://tanakahisateru.hatenablog.jp/entry/2013/12/12/012728

で検証されている内容で、参照渡しの性能がどうしても気になったので、

本当に遅いのか試してみました。

検証コードはほとんど上記ブログのコピペで、

参照渡し後にreturnしないコードを追加しています。

こんな感じ。

<?php

function profile($funcname)
{
$bigarray = range(1, 1000000);

echo $funcname . "\n";

if ($funcname) {
$start = microtime(true);
$ret = $funcname($bigarray, 500000);
$end = microtime(true);
} else {
$start = microtime(true);
$end = microtime(true);
}

echo " caller memory: " . number_format(memory_get_usage()) . "\n";
echo " time: " . (($end - $start) * 1000) . "(ms)\n";
unset($bigarray);
unset($ret);
}

ob_start();
profile(null); // ウォームアップ
ob_end_clean();
// 参照なし
function nop_noref($arr)
{
echo " callee memory: " . number_format(memory_get_usage()) . "\n";
return $arr;
}

// 参照渡しのみ
function nop_ref_arg(&$arr)
{
echo " callee memory: " . number_format(memory_get_usage()) . "\n";
return $arr;
}

// 参照渡し+参照返し
function &nop_ref_both(&$arr)
{
echo " callee memory: " . number_format(memory_get_usage()) . "\n";
return $arr;
}

// 参照渡しでreturnしない
function nop_ref_arg_noreturn(&$arr)
{
echo " callee memory: " . number_format(memory_get_usage()) . "\n";
}

profile('nop_noref');
profile('nop_ref_arg');
profile('nop_ref_both');
profile('nop_ref_arg_noreturn');

実行結果

% php -d memory_limit=-1 test.php

nop_noref
callee memory: 136,495,512
caller memory: 136,495,400
time: 0.016927719116211(ms)
nop_ref_arg
callee memory: 136,495,544
caller memory: 232,884,184
time: 81.586122512817(ms)
nop_ref_both
callee memory: 136,495,608
caller memory: 136,495,496
time: 0.015974044799805(ms)
nop_ref_arg_noreturn
callee memory: 136,496,160
caller memory: 136,496,088
time: 0.016212463378906(ms)

あんまり変わらない気がしますね。。

参照渡ししなければ中で書き換えた瞬間に巨大配列のコピーが発生しますが、

参照渡ししておけば書き換えてもコピーは発生しないので、用途によっては使って良い気がします。

ちなみに上記の各関数のechoの後ろに

$arr[] = null;

を追加すると以下のようになります。

% php -d memory_limit=-1 test.php

nop_noref
callee memory: 136,496,608
caller memory: 232,885,304
time: 80.986022949219(ms)
nop_ref_arg
callee memory: 136,496,632
caller memory: 232,885,416
time: 80.711841583252(ms)
nop_ref_both
callee memory: 136,496,680
caller memory: 136,496,616
time: 0.015974044799805(ms)
nop_ref_arg_noreturn
callee memory: 136,496,712
caller memory: 136,496,688
time: 0.017166137695312(ms)

半年前くらいに書いたコードが不発弾になってるんじゃないかと心配になって確かめたけど、

そんなことはなくてよかった。

検証に使用したのは化石バージョンです。

% php -v

PHP 5.2.17 (cli) (built: Nov 6 2013 15:05:14)