phpdreams

Best Practice: Combining Strings

One of the most common tasks in programming is putting two or more bits of text together to form a single string. There are several ways you can do this, and everybody has their own preferred method. Here and there around the web I've read that style A is better than style B, etc. But what method is really the best?

The idea for this test and post came about recently when I was looking at the DB class for CubeCart. It used sprintf in many places to create the queries, prepare them for use, run them, etc. (this just happened to be the preference of one of the developers) Well, I assumed that using a function to combine two or more strings was slower than concatenating them via 'dot notation' or putting them directly in a double-quoted string, but I wasn't certain. So to validate my thoughts, I wrote another benchmark script.

To test things, I created four string segments that I wished to combine. I then setup a for loop to test each method. Here are the six methods I tested:

Dot Equals
$bigArray[$i] = $text[0];
$bigArray[$i] .= ' ';
$bigArray[$i] .= $text[1];
$bigArray[$i] .= ' ';
$bigArray[$i] .= $text[2];
$bigArray[$i] .= ' ';
$bigArray[$i] .= $text[3];

Dot Concatenation
$bigArray[$i] = $text[0].' '.$text[1].' '.$text[2].' '.$text[3];

In-string Replacement
$bigArray[$i] = "$text[0] $text[1] $text[2] $text[3]";

Complex In-string Replacement
$bigArray[$i] = "{$text2['part1']} {$text2['part2']} {$text2['part3']} {$text2['part4']}";

Function: sprintf()
$bigArray[$i] = sprintf('%s %s %s %s', $text[0], $text[1], $text[2], $text[3]);

Function: implode()
$bigArray[$i] = implode(' ', $text);

Here are the results of the benchmark running each test a million times:

Array Size:1000000 Entries
Dot Equals1.440199 sec
Dot Concatenation0.906687 sec
In-string Replacement0.728721 sec
Complex In-string Replacement0.896465 sec
Function: sprintf()2.155101 sec
Function: implode()0.963101 sec

The results came as a bit of a surprise to me. I figured that sprintf() would be slower, but not more than twice as slow. I ran the same tests over and over with the same overall results each time.

So the conclusion? When you need to combine text strings, if they're just simple variables or numerically indexed array members, then simply including the variable name in your double-quoted text string is the most efficient method. If you're working with an associative array, then the dot notation is just as good since the complex method of putting a variable reference in a string is more difficult to read.

Does any of this make a difference if you're only combining a couple strings in a couple of places? Not really as none of the methods are horribly slow. But if you're building a more complex application that will loop through a lot of data, then choosing the right method could indeed make a difference in the overall runtime of your app which makes both your users and the server admin happier.

Now, while sprintf() is the slowest method, it's also the most powerful as it can do a lot more than just combining a couple of strings. But if you're just gluing a couple of things together, it's a waste of time.

In the end, I rewrote the DB class for CubeCart to eliminate nearly all the sprintf() calls as well as a few other tweaks for efficiency improvements and better debugging output. This updated class should be in their next release, but any V4 user can take advantage of it.

I hope this examination helps somebody. Please comment. :o)

For reference, here's the entire benchmark script:

<?php

// needed to cope with a million entry array
ini_set('memory_limit', '512M');

if($_POST['limit'] && $_POST['limit'] < 1000001) {
	$limit = $_POST['limit'];
} else {
	$limit = 5000;
}

$text[] = "Now is the time";
$text[] = "for all good men";
$text[] = "to come to the aid";
$text[] = "of their country.";

$text2['part1'] = "Now is the time";
$text2['part2'] = "for all good men";
$text2['part3'] = "to come to the aid";
$text2['part4'] = "of their country.";

$bigArray = fillArray($limit);

$max=count($bigArray);

#######################################################

$start = microtime(TRUE);

for($i=0; $i<$max; $i++) {
	$bigArray[$i]  = $text[0];
	$bigArray[$i] .= ' ';
	$bigArray[$i] .= $text[1];
	$bigArray[$i] .= ' ';
	$bigArray[$i] .= $text[2];
	$bigArray[$i] .= ' ';
	$bigArray[$i] .= $text[3];
}

$results['dotequal']['time'] = microtime(TRUE) - $start;
$results['dotequal']['name'] = 'Dot Equals';

#######################################################

$start = microtime(TRUE);

for($i=0; $i<$max; $i++) {
	$bigArray[$i] = $text[0].' '.$text[1].' '.$text[2].' '.$text[3];
}

$results['concat']['time'] = microtime(TRUE) - $start;
$results['concat']['name'] = 'Dot Concatenation';

#######################################################

$start = microtime(TRUE);

for($i=0; $i<$max; $i++) {
	$bigArray[$i] = "$text[0] $text[1] $text[2] $text[3]";
}

$results['replace']['time'] = microtime(TRUE) - $start;
$results['replace']['name'] = 'In-string Replacement';

#######################################################

$start = microtime(TRUE);

for($i=0; $i<$max; $i++) {
	$bigArray[$i] = "{$text2['part1']} {$text2['part2']} {$text2['part3']} {$text2['part4']}";
}

$results['replace2']['time'] = microtime(TRUE) - $start;
$results['replace2']['name'] = 'Complex In-string Replacement';

#######################################################

$start = microtime(TRUE);

for($i=0; $i<$max; $i++) {
	$bigArray[$i] = sprintf('%s %s %s %s', $text[0], $text[1], $text[2], $text[3]);
}

$results['sprintf']['time'] = microtime(TRUE) - $start;
$results['sprintf']['name'] = 'Function: sprintf()';

#######################################################

$start = microtime(TRUE);

for($i=0; $i<$max; $i++) {
	$bigArray[$i] = implode(' ', $text);
}

$results['implode']['time'] = microtime(TRUE) - $start;
$results['implode']['name'] = 'Function: implode()';

#######################################################

echo "<table width=\"400\" cellspacing=\"3\">\n";
echo "<tr><td width=\"50%\"><strong>Array Size:</strong></td><td width=\"50%\"><strong>$limit Entries</strong></td></tr>\n";
foreach($results AS $test) {
	echo "<tr><td>".$test['name']."</td><td>".sprintf("%01.6f", $test['time'])." sec</td></tr>\n";
}
echo "</table>";

echo '<form action="'.$_SERVER['PHP_SELF'].'" method="post">';
echo '<input name="limit" value="'.$limit.'" />';
echo '<input type="submit" value="Update"></form>';
echo '<i>Max Value: 1000000</i>';

#######################################################

function fillArray($limit) {
	global $text;
	// build huge array
	for($i=0; $i<$limit; $i++) {
		$array[] = "$text[0] $text[1] $text[2] $text[3]";
	}
	return $array;
}

?>

Thanks til next time!

blog comments powered by Disqus

What is PHP Dreams?

My name is Bill "Sir William" Wheeler. I am a freelance web developer specializing in PHP & MySQL with a healthy amount of HTML, CSS & JavaScript (jQuery FTW!) thrown in for good measure. I put this site together to share my thoughts and findings with others. I hope to have something for novices and advanced programmers alike.

Bookmark and Share
Follow Me on Twitter
MODx CMS/F