将两个字符串组合在一起的最佳方法是什么?

时间:2009-03-29 18:44:24

标签: php performance string

我读过一些(我在编码错误中认为)将字符串添加到数字中是不好的做法,因为像数字一样,字符串无法更改。因此,将它们一起添加会创建一个新字符串。所以,我想知道,在关注性能时,将两个字符串组合在一起的最佳方法是什么?

这四种中哪一种更好,还是有另一种方式更好?

//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);

甚至重要吗?

12 个答案:

答案 0 :(得分:37)

字符串与点连接绝对是三种方法中最快的一种。无论你喜欢与否,你总是会创建一个新的字符串。 最有可能最快的方式是:

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

不要将它们放在像$result = "$str1$str2";这样的双引号中,因为这会为解析字符串中的符号产生额外的开销。

如果您打算仅使用echo作为输出,那么使用echo的功能可以传递多个参数,因为这不会生成新的字符串:

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

有关PHP如何处理插值字符串和字符串连接check out Sarah Goleman's blog的详细信息。

答案 1 :(得分:13)

您总是要创建一个新的字符串,将两个或多个字符串连接在一起。这不一定是“坏”,但它可能在某些情况下具有性能影响(如紧密循环中的数千/数百万个连接)。我不是一个PHP人,所以我不能给你任何关于连接字符串的不同方法的语义的建议,但对于单个字符串连接(或只是一些),只是让它可读。你不会看到来自少数人的性能损失。

答案 2 :(得分:11)

这是快速而肮脏的测试代码,用于理解性能瓶颈。

单个concat:

$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

作为结论,很明显通过点(。)char的单个concat是最快的。对于案例,当你有很多concats时,表现最好的方法是通过"injection: $inject"语法使用直接字符串注入。

答案 3 :(得分:5)

除非文本真的很大,否则它确实无关紧要。

答案 4 :(得分:3)

正如其他人所说,$str1 . $str2在大多数情况下都是完全可以的,除了(大)循环 请注意,您忽略了一些解决方案:

$output = "$str1$str2";

对于大量字符串,您可以将它们放在一个数组中,并使用implode()从中获取字符串。

哦,“添加字符串”听起来很糟糕,或者至少含糊不清。在大多数语言中,我们更喜欢谈论字符串连接。

答案 5 :(得分:3)

除非在looong循环中使用,否则无关紧要。在通常情况下,即使您丢失了几个处理器周期,也要关注代码可读性。

示例1和2 类似,我认为应该没有太大的区别,这将是所有人的挑战。 1号可能会稍快一些。

示例3 会变慢,因为需要解析sprintf格式('%s%s')。

示例4 执行替换,包括在字符串中搜索 - 需要做的其他事情,需要更多时间。

但首先,串联字符串会出现性能问题吗?这不太可能,您应该分析代码来衡量运行它需要多长时间。然后,用不同的方法替换连接方法。

如果您将其识别为问题,请尝试使用google搜索php字符串构建器类(可以找到一些)或编写自己的。

答案 6 :(得分:2)

发现谷歌的这篇文章,并认为我会运行一些基准,因为我很好奇结果会是什么。 (使用减去自己开销的基准测试程序进行10,000次迭代的基准测试。)

    Which                        2 strings   10 strings   50 strings
    ----------------------------------------------------------------
    $a[] then implode()         2728.20 ps      6.02 μs     22.73 μs
    $a . $a . $a                 496.44 ps      1.48 μs      7.00 μs
    $b .= $a                     421.40 ps ★    1.26 μs      5.56 μs
    ob_start() and echo $a      2278.16 ps      3.08 μs      8.07 μs
    "$a$a$a"                     482.87 ps      1.21 μs ★    4.94 μs ★
    sprintf()                   1543.26 ps      3.21 μs     12.08 μs

所以它里面并不多。如果你需要快速尖叫的话,可能会避免sprintf()implode(),但所有常用方法之间没有太大区别。

答案 7 :(得分:1)

有3种类型的字符串连接操作。

连接,取2个字符串,分配内存大小length1 + length2并将每个复制到新内存中。最快的2个字符串。但是,连接10个字符串则需要9个concat操作。使用的内存为第1个字符串10次,第2个字符串10次,第3个字符串9次,第4个字符串8次等。每个周期使用更多内存运行X + 1 +(X-1)* 2个操作。

sprintf(array_merge,join等),将所有字符串放在一起,加上它们的长度,分配一个大小为sum的新字符串,然后将每个字符串复制到各自的位置。使用的内存是所有初始字符串的2 *长度,操作是2 * X(每个长度,每个副本)

ob(输出缓冲区)分配一个通用的4k块并将每个字符串复制到它。内存4k +每个初始字符串,操作= 2 + X.(开始,结束,每个副本)

选择你的毒药。 OB就像使用内存原子弹加入2个小字符串一样,但是当有很多连接,循环,条件或添加对于干净的sprintf来说太过动态时非常有效。 concat是加入一些固定字符串最有效的方法, sprintf,它可以更好地同时构建一个固定值的字符串。

我不知道在这种情况下php使用哪种例程:“$ x $ y $ z”,可能只是简化为内联$ x。 “”。 $ y。 “”。 $ž

答案 8 :(得分:0)

您阅读的建议可能与echo函数有关,为此可以更快地使用逗号,例如:

echo $str1, $str2;

另一种方法是在变量中建立一个字符串(例如使用。运算符),然后在结尾处回显整个字符串。

你可以使用microtime函数自己测试一下(你需要制作一个循环,重复例如1000或100,000次以使数字显着)。但在你发布的四个中,第一个可能是最快的。它也是最具可读性的 - 其他的在程序上并没有真正的意义。

答案 9 :(得分:0)

这不是2个字符串的解决方案,但是当您考虑以这样的方式加入更多字符串时:

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

创建数组元素并一次加入它们比加入它们要快几百倍。

答案 10 :(得分:0)

我不是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的性能。您需要将字符串附加到列表,以便在非常大的字符串上生效。由于我对php的曝光率有限,我不确定这样的结构是否可用,或者php的数组是否能快速添加新元素。

答案 11 :(得分:0)

在本帖子的最后一篇文章后近两年,我认为以下解决方案对于大量紧密循环来说可能是最快的:

ob_start();

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

$finalstr = ob_get_clean();

此方法可确保所有字符串的平面存储,并且不会产生处理或连接开销。使用最终代码行,您也可以获得整个缓冲区。你可以安全地运行循环而不是独立的回声。