web-dev-qa-db-ja.com

2つの文字列を一緒に追加する最良の方法は何ですか?

私はどこかで(コーディングホラーについて考えました)、文字列を数値のように追加することは悪い習慣であることを読みました。数値と同様に、文字列は変更できないためです。したがって、それらを一緒に追加すると、新しい文字列が作成されます。それで、パフォーマンスに焦点を合わせるときに、2つの文字列を一緒に追加する最良の方法は何ですか?

これらの4つのうちどちらが良いですか、それとももっと良い方法がありますか?

//Note that normally at least one of these two strings is variable
$str1 = 'Hello ';
$str2 = 'World!'; 
$output1 = $str1.$str2; //This is said to be bad

$str1 = 'Hello ';
$output2 = $str1.'World!'; //Also bad

$str1 = 'Hello';
$str2 = 'World!';
$output3 = sprintf('%s %s', $str1, $str2); //Good?
//This last one is probaply more common as:
//$output = sprintf('%s %s', 'Hello', 'World!');

$str1 = 'Hello ';
$str2 = '{a}World!';
$output4 = str_replace('{a}', $str1, $str2);

それも重要ですか?

21
Pim Jager

2つ以上の文字列を連結した新しい文字列を常に作成します。これは必ずしも「悪い」とは限りませんが、特定のシナリオでパフォーマンスに影響を与える可能性があります(タイトループでの数千/数百万の連結など)。私はPHP=男ではないので、文字列を連結するさまざまな方法のセマンティクスについてはアドバイスできませんが、単一の文字列連結(またはいくつか)の場合は、それらの数が少ないことによるパフォーマンスへの影響はありません。

13
Ed S.

ドットを使用した文字列連結は、3つの方法の中で最も速い方法です。好きかどうかにかかわらず、常に新しい文字列を作成します。おそらく最も速い方法は次のとおりです。

$str1 = "Hello";
$str1 .= " World";

$result = "$str1$str2";のように二重引用符で囲まないでください。文字列内のシンボルを解析するための追加のオーバーヘッドが発生します。

これをエコーでの出力にのみ使用する場合は、新しい文字列を生成しないため、複数のパラメーターに渡すことができるエコーの機能を使用します。

$str1 = "Hello";
$str2 = " World";
echo $str1, $str2;

PHPが補間された文字列と文字列の連結をどのように扱うかについての詳細は Sarah Golemanのブログをご覧ください

37

以下は、パフォーマンスのボトルネックを理解するための、迅速でダーティなテストコードです。

単一の連結:

$iterations = 1000000;
$table = 'FOO';
$time = microtime(true);
for ($i = 0; $i < $iterations; $i++) {
        $sql = sprintf('DELETE FROM `%s` WHERE `ID` = ?', $table);
}
echo 'single sprintf,',(microtime(true) - $time)."\n";

$time = microtime(true);
for ($i = 0; $i < $iterations; $i++) {
        $sql = 'DELETE FROM `' . $table . '` WHERE `ID` = ?';
}
echo 'single concat,',(microtime(true) - $time)."\n";

$time = microtime(true);
for ($i = 0; $i < $iterations; $i++) {
        $sql = "DELETE FROM `$table` WHERE `ID` = ?";
}
echo 'single "$str",',(microtime(true) - $time)."\n";

私はこれらの結果を得ます:

single sprintf,0.66322994232178
single concat,0.18625092506409 <-- winner
single "$str",0.19963216781616

多くの連結(10):

$iterations = 1000000;
$table = 'FOO';
$time = microtime(true);
for ($i = 0; $i < $iterations; $i++) {
        $sql = sprintf('DELETE FROM `%s`,`%s`,`%s`,`%s`,`%s`,`%s`,`%s`,`%s`,`%s`,`%s` WHERE `ID` = ?', $table, $table, $table, $table, $table, $table, $table, $table, $table, $table);
}
echo 'many sprintf,',(microtime(true) - $time)."\n";

$time = microtime(true);
for ($i = 0; $i < $iterations; $i++) {
        $sql = 'DELETE FROM `' . $table . '`,`' . $table . '`,`' . $table . '`,`' . $table . '`,`' . $table . '`,`' . $table . '`,`' . $table . '`,`' . $table . '`,`' . $table . '`,`' . $table . '` WHERE `ID` = ?';
}
echo 'many concat,',(microtime(true) - $time)."\n";

$time = microtime(true);
for ($i = 0; $i < $iterations; $i++) {
        $sql = "DELETE FROM `$table`,`$table`,`$table`,`$table`,`$table`,`$table`,`$table`,`$table`,`$table`,`$table` WHERE `ID` = ?";
}
echo 'many "$str",',(microtime(true) - $time)."\n";

結果:

many sprintf,2.0778489112854
many concats,1.535336971283
many "$str",1.0247709751129 <-- winner

結論として、ドット(。)文字による単一の連結が最も速いことが明らかになります。また、多くの連結がある場合、"injection: $inject"構文による直接文字列インジェクションを使用するのが最適な方法です。

11
Aleksandr Makov

本当に大量のテキストでない限り、それは本当に重要ではありません。

5
Toby Allen

他の人が言ったように、$str1 . $str2は、(大きな)ループを除いて、ほとんどの場合完全に問題ありません。
いくつかのソリューションを見落としていることに注意してください:

$output = "$str1$str2";

また、多数の文字列の場合は、それらを配列に入れ、implode()を使用してそれらから文字列を取得できます。

ああ、「文字列を追加する」というのは悪いように思えるか、少なくともあいまいです。ほとんどの言語では、文字列の連結について話します。

3
PhiLho

ルーンループで使用されない限り、それは問題ではありません。通常、プロセッササイクルが複数失われた場合でも、コードの読みやすさに重点を置きます。

例1と2は似ていますが、大きな違いはないと思います。これがすべての断食になります。 No. 1は少し速いかもしれません。

は、sprintf形式( '%s%s')を解析する必要があるため、遅くなります。

例4置換を実行します。これは文字列内の検索を含みます-追加の処理には、より多くの時間がかかります。

しかし、最初に、文字列の連結はパフォーマンスの問題ですか?それは非常にまれです、それを実行するのにかかる時間を測定するコードをプロファイルする必要があります。次に、連結方法を別の方法に置き換え、もう一度やり直します。

問題として特定した場合は、php文字列ビルダークラスを探してみてください(見つかるはずです)、または独自に作成してください。

3
ya23

Googleからこの投稿が見つかりました。結果がどうなるか知りたくて、いくつかのベンチマークを実行すると思いました。 (独自のオーバーヘッドを差し引くベンチマーカーを使用して、10,000以上の反復をベンチマークしました。)

どの2ストリング10ストリング50ストリング
 --------------------------------- ------------------------------- 
 $ a []次に、implode()2728.20 ps 6.02μs22.73μs 
 $ a。 $ a。 $ a 496.44 ps 1.48μs7.00μs
 $ b。= $ a 421.40 ps★1.26μs5.56μs
 ob_start()and echo $ a 2278.16 ps 3.08μs8.07μs
 " $ a $ a $ a "482.87 ps 1.21μs★4.94μs★
 sprintf()1543.26 ps 3.21μs12.08μs

だからそこには多くはありません。何かを速く叫ぶ必要がある場合は、sprintf()implode()を回避することをお勧めしますが、すべての通常のメソッド間に大きな違いはありません。

2
Dave Houlbrooke

文字列の結合操作には3つのタイプがあります。

連結し、2つの文字列を取り、メモリサイズlength1 + length2を割り当て、それぞれを新しいメモリにコピーします。 2弦の最速。ただし、10個の文字列を連結するには、9個の連結操作が必要です。使用されるメモリは、1番目の文字列を10回、2番目の文字列を10回、3番目の文字列を9回、4番目の文字列を8回などです。各サイクルでより多くのメモリを使用してX + 1 +(X-1)* 2演算を実行します。

sprintf(array_merge、joinなど)、すべての文字列をまとめて、それらの長さを合計し、サイズが合計の新しい文字列を割り当て、各文字列をそれぞれの場所にコピーします。使用されるメモリはすべての初期文字列の2 * lengthであり、操作は2 * X(各長さ、各コピー)

ob(出力バッファー)は、一般的な4kチャンクを割り当て、各文字列をそこにコピーします。メモリ4k +各初期文字列、操作= 2 + X(開始、終了、各コピー)

毒を選びなさい。 OBは、メモリを使用するようなものですatom爆弾で2つの小さな文字列を結合しますが、結合、ループ、条件が多数ある場合、または追加が動的すぎてクリーンなsprintfを実行できない場合に非常に効果的です。いくつかの固定文字列を結合するのに最も効率的です。sprintfは、一度に固定値から文字列を作成するのに適しています。

この状況でphpがどのルーチンを使用するかはわかりません。「$ x $ y $ z」は、インライン$ xに削減される可能性があります。 "" $ y。 "" $ z

1
ppostma1

あなたが読んだアドバイスはecho関数に関連している可能性があります。そのため、コンマを使用する方が速いです。例:

echo $str1, $str2;

別のアプローチは、変数に文字列を作成し(たとえば、。演算子を使用)、最後に文字列全体をエコーすることです。

これは、microtime関数を使用して自分でテストできます(数値を有意にするために、たとえば1,000回または100,000回繰り返すループを作成する必要があります)。しかし、あなたが投稿した4つのうち、最初のものが最も速い可能性があります。また、それは最も読みやすいものです-他の人はプログラム的に意味をなさない。

0
DisgruntledGoat

これは2つの文字列の解決策ではありませんが、より多くの文字列をそのように結合することを考えた場合、次のようになります。

$tmp=srray();
for(;;) $tmp[]='some string';
$str=implode('',$tmp);

配列要素を作成して一度に結合する方が、100回結合するよりも高速です。

0
Thinker

私はPHP達人ではありませんが、他の多くの言語(Pythonなど)では、多くの小さい文字列から長い文字列を作成する最も速い方法は、連結したい文字列を追加することですリストに組み込み、次に組み込みの結合メソッドを使用してそれらを結合します。次に例を示します。

$result = array();
array_Push("Hello,");
array_Push("my");
array_Push("name");
array_Push("is");
array_Push("John");
array_Push("Doe.");
$my_string = join(" ", $result);

タイトなループで巨大な文字列を作成する場合、それを行う最も速い方法は、配列に追加し、最後に配列を結合することです。

注:この説明全体は、array_Pushのパフォーマンスにかかっています。これを非常に大きな文字列で有効にするには、文字列をlistに追加する必要があります。私のphpへのエクスポージャーは限られているため、そのような構造が使用可能かどうか、またはphpの配列が新しい要素を追加する速度が速いかどうかはわかりません。

0
shadanan

このスレッドの最後の投稿から約2年間、以下の解決策が膨大な数のタイトなループに対して最も高速であると思います:

ob_start();

echo $str1;
echo $str2;
.
.
.
echo $str_n;

$finalstr = ob_get_clean();

このメソッドは、すべての文字列のフラットストレージを保証し、処理や連結のオーバーヘッドを防ぎます。最後のコード行では、バッファ全体も取得します。独立したエコーの代わりにループを安全に実行できます。

0
Eric Joyce