At one point in time, I spent hours troubleshooting why my argument swapping/repeated placeholders in
printf statements weren’t working properly. I referred to the PHP docs, the internet, cursed the fact that I was doing back-end coding again, etc., and finally gave up and just repeated my variables using normal, un-numbered conversion specifications. Not once did I see anything that answered my question: “Why am I getting a ‘Too few arguments’ warning when using numbered placeholders?”
So, why am I getting a ‘Too few arguments’ warning when using numbered placeholders?
I (and probably you) was/were/are using a double-quoted string.
The issue here is with how PHP handles the String type. PHP is pretty forgiving about a lot of things, and in many cases single-quoted strings and double-quoted strings work just as well as the other. But there are some very important differences, especially when it comes to special characters, conversion specifications and variables.
If you’re having this same problem, change to using single quotes. Voilà, your problem is probably fixed, as long as you didn’t forget to escape any single quotes within your string.
A little more information on strings
The number one thing to remember when working with single-quoted strings in PHP: the only parsed character is the escaped single quote [\'].
Double-quoted strings will parse many escape sequences, and most importantly will expand variables.
If you’re a visual learner, refer to this example:
print '\nHello $username'; print "\nHello $username";
The above code will produce the following (assuming
$username has been set to “World”):
So why is this an issue with
I haven’t actually found a source to explain this or verify my postulate. But, I’d bet money on it, and I’m not a betting woman.
Double-quoted strings expand the conversion specification as a variable before
printf even gets a chance to evaluate the code. Visually speaking:
$s = "shoes"; $numchucks = "a"; $noun = "wood"; $verb = "chuck"; printf("How much %1$s would %2$s %1$s-%3$s %3$s...",$noun,$numchucks,$verb);
The above code results in a “Too few variables” warning, and nothing prints because
printf is actually getting a string that looks like: “
How much %1shoes would %2shoes %1shoes-%3shoes %3shoes...” In other words, you’re passing it five valid conversion specifications but only four arguments. If you added in the proper number of arguments, like this:
printf("How much %1$s would %2$s %1$s-%3$s %3$s...",$noun,$numchucks,$verb,$noun,$verb);
The resulting output would be:
How much woodhoes would ahoes chuckhoes-woodhoes chuckoes…
For those readers who are familiar with only the most basic of conversion specs,
%2s is perfectly valid. It reads like: “format as a string [s] at least two characters long , using the default padding character [a space] and default alignment [left].” So, as you see with ‘a’, it pads the left of the value with a space (exaggerated in above example with three spaces).
In the above examples, we end up with a (somewhat) sensibly formatted string because our interpreted variable
$s started with the letter ‘s’, a valid conversion specification character. You will end up with even weirder results if
$s begins with an invalid conversion spec character. Take
$s="random"; for example.
printf tries to use ‘r’ but as it’s not a valid spec character it just leaves out the conversion specifications
How much andom would andom andom-andom andom…
Even more descriptive is if
$s doesn’t exist:
How much would…
So, for future reference, if you want to use numbered conversion specifications, here’s the proper way:
printf('How much %1$s would %2$s %1$s-%3$s %3$s...',$noun,$numchucks,$verb);
And you know, I’ve really always wondered—
How much wood would a wood-chuck chuck…
…if a wood-chuck could chuck wood.