Tom Butler's programming blog

Stop the sprintf() abuse

sprintf

While there are some very valid uses for sprintf I often see it overused/abused.

People like to claim it produces more readable code than string concatenation. However, I wholly disagree

Lets take a simple example.

$str = sprinf('Hi, %s you last logged in on %s', $name, $date);

Nice and simple, but is it really any more readable than

$str = 'Hi, ' . $name . ' you last logged in on ' . $date;

This code, although it has the concatenation can be read in order as if it's english. This vastly improves readability and is why it's superior to sprintf

I've seen people use sprintf with 20+ parameters. That is a maintainability nightmare; if you want to add a new string in at position 12 there is a lot of working out to do:

  • Add the new %s
  • count how many variables it is into the string
  • find the position in the parameter list and add it to the sprintf call.

This involves an awful lot of pointless counting and vastly slows down development. With concatenation you simply add the concatenation in the correct place and it's done.

Readability is also improved because you don't have to do a mental match up with the parameters you can read it as if it's english.

Performance

The other thing to consider is performance. I've created a very simple benchmark:

<?php $iterations = 500000; $name = 'Tom'; $date = '13/09/2009'; $t1 = microtime(true); for ($i = 0; $i < $iterations; $i++) { $str = sprintf('Hi %s, you last logged in on %s.', $name, $date); } $t2 = microtime(true); echo 'sprintf: ' . ($t2-$t1); echo '<br />'; $t1 = microtime(true); for ($i = 0; $i < $iterations; $i++) { $str = 'Hi ' . $name . ', you last logged in on ' . $date; } $t2 = microtime(true); echo 'concat: ' . ($t2-$t1); echo '<br />'; ?>

Which produces the result:

sprintf: 0.61469507217407 concat: 0.26952886581421

Concatenation is far faster (almost 2.5x in this example), obviously there is far less processing involved. As you add more variables, sprintf gets slower and slower compared with concatenation.

Of course performance isn't the be all and end all of good code. But coupled with the other reasons I see no reason to use sprintf in most cases.

So when should sprintf be used.

SQL?

No. Ideally you should be using PDO anyway which has named parameters that work similarly to sprintf(). This still suffers from reduced readability (It at least uses named parameters though! No %s meaning the supplied arguments don't need to be in order!) but the security advantages alone far outweigh this. If you're not using PDO you should be using a function which maps all query parameters through the relevant *_escape_string function and work similarly to PDO.

Direct variable substitution in arbitrary strings

No. As above.

When formatting numbers in strings.

Perhaps. Sometimes sprintf may seem like the best solution, but it's likely you'll want a site-wide number format for currencies, etc so sprintf may not always be the best choice.

Re-usable non-static strings. e.g. language files

Yes. This is a good example of where sprintf should be used. There are not likely to be more than a few replacements and they are unlikely to change. This also makes the strings easy to separate out and send off to a translator. If you have multiple language files, it's likely that due to grammar the strings will need to have arguments. Often these arguments may be in a different order sprintf() supports this too. This is a perfect candidate for sprintf.