えっと、先日某所より
「ループ内では、「.=」で文字列連結しないでarrayの要素に一つずつ値を突っ込んで、ループ抜けた後にimpludeせよ」
的なお話をいただいたのですが、
「確かに速いかもしれないけど、メモリ的にはどうよ?」とも思いましたので、
これはちょっと検証してみましょうという記事です。
検証に使ったPHPのバージョンは、5.4.8です。
じゃあ、まずは「.=」での連結から。
-----------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------
<?phpfunction diff_microtime($start, $end)
{
list($start_m, $start_t) = explode(' ', $start);
list($end_m, $end_t) = explode(' ', $end);
return ((float)$end_t + (float)$end_m) - ((float)$start_t + (float)$start_m);
}var_dump(memory_get_usage());
var_dump(memory_get_usage(true));
var_dump(memory_get_peak_usage());
var_dump(memory_get_peak_usage(true));$start = microtime();
$str = '';
for ($i = 0; $i < 100000; $i++)
{
$str .= 'a';
}$end = microtime();
echo diff_microtime($start, $end) . "\n";
var_dump(memory_get_usage());
var_dump(memory_get_usage(true));
var_dump(memory_get_peak_usage());
var_dump(memory_get_peak_usage(true));
実行結果は以下の通り。
int(228664)
int(262144)
int(231608)
int(262144)
0.016595125198364
int(329440)
int(524288)
int(332456)
int(524288)
次に、「= 変数 . 連結したい文字列」の連結。
さっきと同じソースの箇所は省略しています。
-----------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------
〜略〜$str = '';
for ($i = 0; $i < 100000; $i++)
{
$str = $str . 'a';
}〜略〜
実行結果は、
int(228712)
int(262144)
int(231608)
int(262144)
0.68254494667053
int(329480)
int(786432)
int(465864)
int(786432)
う〜ん、明らかに遅いですねぇ。ということで却下かと。
で、ちょっと気になったのは、まぁ本題と関係ないんですけど、
ループを抜けた後の「memory_get_usage(true)」と「memory_get_peak_usage()」の値。
まず前者については、memory_get_usage()の値はほぼ同じなのに、
なんで、こんなに差異が生じてしまっているのかと。
後者は、memory_get_peak_usage(true)の値がほぼ同じなのに、
なんで、こんなに差異が・・・以下略。
う〜ん、分からないですねぇ。マニュアルにはemalloc()と書いてあるので、
C言語の知識が必要かもしれませんね。
まぁ、勉強ですね。
最近は、師匠も教えてくれなくなってきましたしねぇw
次は、こんな形。
-----------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------
〜略〜$str = '';
for ($i = 0; $i < 100000; $i++)
{
$str = "{$str}a";
}〜略〜
実行結果は、
int(228720)
int(262144)
int(231608)
int(262144)
0.53206992149353
int(329488)
int(786432)
int(565888)
int(786432)
これまた遅いですね。
次は、array_pushを使ったケース。
-----------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------
〜略〜$arr = array();
for ($i = 0; $i < 100000; $i++)
{
array_push($arr, 'a');
}$str = implode('', $arr);
〜略〜
実行結果。
int(229216)
int(262144)
int(231608)
int(262144)
0.071195125579834
int(18178848)
int(18612224)
int(18183968)
int(18612224)
うん、確かに遅くはないですけど、やっぱりメモリが〜ですね。
最後に、array_pushを使わない配列への要素の追加のケース。
-----------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------
〜略〜$arr = array();
for ($i = 0; $i < 100000; $i++)
{
$arr[] = 'a';
}$str = implode('', $arr);
〜略〜
実行結果。
int(229088)
int(262144)
int(231608)
int(262144)
0.1010959148407
int(18179280)
int(18612224)
int(18181992)
int(18612224)
array_pushを使った時と、殆ど変わらないですね。
ということで結論。
「.=」での文字列連結が、速度的にもメモリ的にも一番良いと思います。
まぁ、「unsetすれば配列使っても問題ないだろ」ってツッコミに対しては、
「unsetを書き忘れたら?」って反論で終わりだと思いますしね。
書かなくて問題ないなら、書かない方が良いでしょ?
あと、最初に書いた発言は、多分PHPのバージョンが古かったか、
検証方法が上記とは違うやり方だった(と言われても、どういうやり方よって話ですけど)か、
単純に検証が甘かったかのいずれかじゃないですかね。
個人的予想では、検証が甘かったに一票を投じますけど B-p
ああ、あと文字列連結の実装方法は、上記以外にもあるのかなぁっていう疑問も少しありますね。
まぁ、もし見つけたら、また検証してみたいと思います。