22

I read somewehere (I thought on codinghorror) that it is bad practice to add strings together as if they are numbers, since like numbers, strings cannot be changed. Thus, adding them together creates a new string. So, I was wondering, what is the best way to add two strings together, when focusing on performance?

Which of these four is better, or is there another way which is better?

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

Does it even matter?

jball
  • 24,791
  • 9
  • 70
  • 92
Pim Jager
  • 31,965
  • 17
  • 72
  • 98

12 Answers12

38

String Concatenation with a dot is definitely the fastest one of the three methods. You will always create a new string, whether you like it or not. Most likely the fastest way would be:

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

Do not put them into double-quotes like $result = "$str1$str2"; as this will generate additional overhead for parsing symbols inside the string.

If you are going to use this just for output with echo, then use the feature of echo that you can pass it multiple parameters, as this will not generate a new string:

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

For more information on how PHP treats interpolated strings and string concatenation check out Sarah Goleman's blog.

Patrick Glandien
  • 7,791
  • 5
  • 41
  • 47
12

Here's the quick and dirty test code, to understand the performance bottlenecks.

Single 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";

I get these results:

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

Many concats (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";

Results:

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

As conclusion, it becomes obvious that single concat via dot (.) char is the fastest. And for cases, when you've got many concats, the best performing method is using direct string injection via "injection: $inject" syntax.

Aleksandr Makov
  • 2,820
  • 3
  • 37
  • 62
  • 1
    well, I wouldn't say it's "obvious that single concat via dot (.) char is the fastest" - ~10% time difference on a microbenchmark like this is actually negligible. I'd say that since you proven "$str" to be the fastest way with growing amount of concats (with a visible 50% time difference), you should rather say that "$str" is usually the preferred way to concat strings... –  Apr 12 '14 at 16:23
12

You are always going to create a new string whe concatenating two or more strings together. This is not necessarily 'bad', but it can have performance implications in certain scenarios (like thousands/millions of concatenations in a tight loop). I am not a PHP guy, so I can't give you any advice on the semantics of the different ways of concatenating strings, but for a single string concatenation (or just a few), just make it readable. You are not going to see a performance hit from a low number of them.

Ed S.
  • 122,712
  • 22
  • 185
  • 265
5

Unless its really large amount of text it really doesnt matter.

Toby Allen
  • 10,997
  • 11
  • 73
  • 124
3

As the others said, $str1 . $str2 is perfectly OK in most cases, except in (big) loops.
Note that you overlook some solutions:

$output = "$str1$str2";

and for large number of strings, you can put them in an array, and use implode() to get a string out of them.

Oh, and "adding strings" sounds bad, or at least ambiguous. In most languages, we prefer to speak of string concatenation.

PhiLho
  • 40,535
  • 6
  • 96
  • 134
  • 1
    Ah ok, I'm not a native english speaker so I knew it was something like that word, but I kept thinking concentating (which is a completely different word (is it even a word?)) – Pim Jager Mar 29 '09 at 19:00
3

It doesn't matter unless used in a looong loop. In usual cases focus on code readability, even if you lost several processor cycles.

Example 1 and 2 are similar, I don't think there should be much difference, this would be the fastes of all. No. 1 might be slightly faster.

Example 3 will be slower, as sprintf format ('%s %s') needs to be parsed.

Example 4 does the replace, which involves searching within a string - additional thing to do, takes more time.

But firstly, is concatenating strings a performance problem? It's very unlikely, you should profile code to measure how much time does it take to run it. Then, replace the concatenating method with a different one and time again.

If you identify it as a problem, try googling for php string builder class (there are some to be found) or write your own.

ya23
  • 14,226
  • 9
  • 46
  • 43
2

Found this post from Google, and thought I'd run some benchmarks, as I was curious what the result would be. (Benchmarked over 10,000 iterations using a benchmarker that subtracts its own overhead.)

    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

So there's not much in it. Probably good to avoid sprintf() and implode() if you need something to be screaming fast, but there's not much difference between all the usual methods.

1

there are 3 types of string joining operations.

Concatenate, take 2 string, allocate memory size length1+length2 and copy each into the new memory. quickest for 2 strings. However, concatenating 10 strings then requires 9 concat operations. The memory used is the 1st string 10 times, 2nd string 10 times, 3rd string 9 times, 4th string 8 times, etc. Runs X+1 +(X-1)*2 operations using more memory each cycle.

sprintf (array_merge, join, etc), take all the strings together, sum their length, allocate a new string of size sum, then copy each string into its respective place. memory used is 2*length of all initial strings, and operations is 2*X (each length, each copy)

ob (output buffer) allocate a generic 4k chunk and copies each string to it. memory 4k + each initial string, operations = 2 + X. (start, end, each copy)

Pick your poison. OB is like using a memory atom bomb to join 2 small strings, but is very effective when there are many joins, loops, conditions or the additions are too dynamic for a clean sprintf. concat is the most efficient to join a few fixed strings, sprintf which works better for building a string out of fixed values at one time.

I don't know which routine php uses in this situation: "$x $y $z", might just be reduced to an inline $x . " " . $y . " " . $z

ppostma1
  • 3,616
  • 1
  • 27
  • 28
0

I'm not a PHP guru, however, in many other languages (e.g. Python), the fastest way to build a long string out of many smaller strings is to append the strings you want to concatenate to a list, and then to join them using a built-in join method. For example:

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

If you are building a huge string in a tight loop, the fastest way to do it is by appending to the array and then joining the array at the end.

Note: This entire discussion hinges on the performance of an array_push. You need to be appending your strings to a list in order for this to be effective on very large strings. Because of my limited exposure to php, I'm not sure if such a structure is available or whether php's array is fast at appending new elements.

shad
  • 1,770
  • 13
  • 12
0

The advice you have read may have been related to the echo function, for which it's quicker to use commas, eg:

echo $str1, $str2;

Another approach is to build up a string in a variable (eg using the . operator) then echo the whole string at the end.

You could test this yourself using the microtime function (you'll need to make a loop that repeats eg 1,000 or 100,000 times to make the numbers significant). But of the four you posted, the first one is likely to be the fastest. It's also the most readable - the others don't really make sense programmatically.

DisgruntledGoat
  • 70,219
  • 68
  • 205
  • 290
0

This is not a solution for 2 strings, but when you thinking of joining more strings best way like that:

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

It's faster to create array element and join them all at once, than join them hundred times.

Thinker
  • 14,234
  • 9
  • 40
  • 55
0

For nearly 2 years after last post in this thread, I think that below solution may be the fastest for huge number of tight loops:

ob_start();

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

$finalstr = ob_get_clean();

This method ensures a flat storage of all strings and no processing or concatenation overhead. With the final code line, you get entire buffer as well. You can safely run loops instead of independent echos.

  • But this means you can't print any real output during this part of your program. It seems like a real kludge, and the `join` answer is probably just as good. – Barmar Nov 09 '12 at 02:12