代码之家  ›  专栏  ›  技术社区  ›  Pim Jager

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

  •  20
  • Pim Jager  · 技术社区  · 16 年前

    我读到一些东西(我在编写恐怖代码时想到),把字符串加在一起就好像它们是数字一样是不好的做法,因为和数字一样,字符串是不能改变的。因此,将它们加在一起会创建一个新的字符串。所以,我想知道,在关注性能时,将两个字符串组合在一起的最佳方法是什么?

    这四个中哪一个更好,或者有其他更好的方法吗?

    //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 回复  |  直到 7 年前
        1
  •  13
  •   Ed Swangren    16 年前

    当将两个或多个字符串连接在一起时,总是要创建一个新的字符串。这不一定是“坏的”,但在某些情况下(比如在一个紧密的循环中有成千上万个连接),它可能会影响性能。我不是一个php人,所以我不能给你任何关于连接字符串的不同方式语义的建议,但是对于单个字符串连接(或只是几个),只需使其可读即可。你不会看到他们中的一小部分人的表现受到影响。

        2
  •  37
  •   Patrick Glandien    16 年前

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

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

    不要像这样用双引号括起来 $result = "$str1$str2"; 因为这将产生额外的开销来解析字符串中的符号。

    如果您只想将其用于echo输出,那么可以使用echo的特性来传递多个参数,因为这样不会生成新的字符串:

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

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

        3
  •  11
  •   Aleksandr Makov    12 年前

    下面是快速而肮脏的测试代码,了解性能瓶颈。

    单一集合:

    $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
    

    综上所述,通过点(.)字符的单个concat是最快的。对于一些情况,当你有很多海螺的时候,最好的方法是通过 "injection: $inject" 语法。

        4
  •  5
  •   Toby Allen mercator    16 年前

    除非它的文本量真的很大,否则它真的不重要。

        5
  •  3
  •   PhiLho    16 年前

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

    $output = "$str1$str2";
    

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

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

        6
  •  3
  •   ya23 devoured elysium    16 年前

    除非用在龙圈里,否则没关系。在通常情况下,关注代码可读性,即使您丢失了几个处理器周期。

    例1和2 是相似的,我不认为有什么区别,这将是所有的禁食。1号可能稍微快一点。

    例3 将变慢,因为需要分析sprintf格式(“%s%s”)。

    例4 替换(包括在字符串中搜索)是否需要花费更多的时间?

    但首先,串接是一个性能问题吗?这是非常不可能的,您应该分析代码以测量运行它需要多少时间。然后,用一个不同的连接方法替换连接方法,然后再次替换。

    如果您认为这是一个问题,请尝试在Google上搜索php字符串生成器类(可以找到一些类)或编写自己的类。

        7
  •  2
  •   Dave Houlbrooke    7 年前

    在谷歌上找到了这篇文章,我想我会做一些基准测试,因为我很好奇结果会是什么。(使用减去自身开销的基准标记对10000次迭代进行基准化。)

        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() 如果你需要一些东西快速的尖叫,但是所有的常规方法没有太大的区别。

        8
  •  1
  •   ppostma1    13 年前

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

    连接,取2个字符串,分配内存大小length1+length2,然后将每个字符串复制到新内存中。2根弦最快。但是,连接10个字符串需要9个concat操作。使用的内存是第一个字符串10次、第二个字符串10次、第三个字符串9次、第四个字符串8次等。每个周期运行x+1+(x-1)*2个使用更多内存的操作。

    sprintf(数组合并、联接等),将所有字符串放在一起,求和它们的长度,分配一个新的大小和字符串,然后将每个字符串复制到各自的位置。使用的内存是所有初始字符串的2*长度,操作是2*x(每个长度,每个副本)

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

    挑选你的毒药。 ob类似于使用内存原子弹连接2个小字符串,但是当有许多连接、循环、条件或添加对于干净的sprintf来说太动态时,它非常有效。 concat是连接几个固定字符串的最有效方法, sprintf可以更好地一次用固定值构建字符串。

    我不知道在这种情况下PHP使用的是哪一个例程:“$x$y$z”,可能会被简化为内联$x。“Y”。$Z

        9
  •  0
  •   DisgruntledGoat    16 年前

    你读过的建议可能与 echo 函数,使用逗号更快,例如:

    echo $str1, $str2;
    

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

    你可以使用微时间函数自己测试这个(你需要做一个循环,重复1000或100000次,使数字有效)。但在你发布的四篇文章中,第一篇可能是最快的。它也是最易读的——其他的在程序上没有真正意义。

        10
  •  0
  •   Thinker    16 年前

    这不是针对2个字符串的解决方案,但当您考虑以这样的最佳方式连接更多字符串时:

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

    创建数组元素并同时连接它们比连接它们一百次快。

        11
  •  0
  •   shad    15 年前

    但是,在许多其他语言(如python)中,我不是php专家,用许多较小的字符串构建长字符串的最快方法是将要连接到列表中的字符串附加到列表中,然后使用内置的join方法将它们连接起来。例如:

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

    如果您在一个紧密的循环中构建一个巨大的字符串,最快的方法是追加到数组,然后在末尾加入数组。

    注意:整个讨论取决于数组推送的性能。您需要将字符串附加到 列表 以便在非常大的字符串上有效。由于我对PHP的了解有限,我不确定这样的结构是否可用,或者PHP的数组是否能够快速附加新元素。

        12
  •  0
  •   Eric Joyce    13 年前

    在这篇文章的最后一篇文章发表近2年后,我认为下面的解决方案对于大量的紧密循环来说可能是最快的:

    ob_start();
    
    echo $str1;
    echo $str2;
    .
    .
    .
    echo $str_n;
    
    $finalstr = ob_get_clean();
    

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