Strings7 min readExamples run on PHP 8.5.10

printf()

Learn how PHP 8.4 printf() formats and prints values with padding, precision and argument numbering, what it returns, and which mistakes to avoid.

Signature

printf(string $format, mixed ...$values): int

Purpose

printf() builds a string from a template and sends it straight to the output. The template holds ordinary text plus placeholders called conversion specifications. Each placeholder says which value to insert and how to present it: padded, rounded, in hexadecimal, and so on. Use it when layout matters, such as aligned columns, fixed decimals or zero-padded codes. If you need the result as a string instead of printing it, use sprintf().

Signature

Parameters

$format is the template. Everything except % is copied unchanged. A placeholder follows this shape:

%[argnum$][flags][width][.precision]specifier

  • argnum: an integer followed by $, selecting which argument to use. This lets you reuse or reorder values.
  • flags: - left-justifies, + always shows a sign, 0 pads with zeros, a space pads with spaces (the default), and 'x pads with the character x.
  • width: the minimum number of characters. A * takes the width from an extra integer argument.
  • precision: a period plus a number. For f, F, e and E it is the digits after the decimal point (6 by default). For s it is a maximum length that truncates the string.
  • specifier: the conversion type. Common ones are d (signed integer), u (unsigned), s (string), f/F (float), e/E (scientific), b, o, x, X (binary, octal, hex), c (character from a code) and % (a literal percent sign).

...$values holds the arguments, in the order the placeholders consume them. Values are coerced to the type the specifier needs.

Return value and failure cases

The function returns an int: the length of the string it output. Since PHP 8.0 it no longer returns false. Problems throw exceptions instead:

  • ValueError when no arguments are given, or when a width or precision is out of range.
  • ArgumentCountError when the template needs more arguments than you supplied.

Example 1: output and return value

The return value counts the characters that were printed, including the newline in the template.

Example
<?php
$length = printf("%s has %d items\n", "Cart", 3);
echo $length, "\n";
Output
Cart has 3 items
17

Example 2: aligned columns

A width with - left-aligns text. A width with a precision gives right-aligned fixed decimals. The 0 flag pads the quantity with zeros.

Example
<?php
$rows = [["Pen", 1.5, 3], ["Notebook", 12.25, 10]];
foreach ($rows as [$name, $price, $qty]) {
    printf("%-10s|%8.2f|%03d\n", $name, $price, $qty);
}
Output
Pen       |    1.50|003
Notebook  |   12.25|010

Example 3: argument numbers, literal percent, padding and hex

Argument numbers let the template use values out of order. In a double-quoted PHP string, write the dollar sign as \$ so PHP does not try to interpolate a variable.

Example
<?php
printf("%2\$s scored %1\$d%% (%3\$s)\n", 87, "Ana", "pass");
printf("#%02X%02X%02X\n", 255, 128, 0);
printf("[%'*8s]\n", "php");
printf("[%5.1s]\n", "hello");
Output
Ana scored 87% (pass)
#FF8000
[*****php]
[    h]

Edge cases

  • %c ignores padding and width, so it is only useful for single characters.
  • Width and precision count bytes, not visible characters. Padding or truncating multibyte text such as UTF-8 can cut a character in half or misalign output. Use multibyte-aware functions for that text.
  • %u shows a negative integer as its large unsigned equivalent.
  • %f respects the current locale, while %F does not. Prefer %F when the decimal separator must always be a period.
  • %d converts its argument to an integer, so a float loses its fractional part and a non-numeric string becomes 0.
  • With the 0 flag on a string placeholder, zeros are added to the right side when you combine it with left-justification.
  • Mixing numbered and unnumbered placeholders in one template is easy to get wrong. Choose one style per template.

Common mistakes

  1. Passing untrusted text as the format. Calling printf($userInput) treats any % in the input as a directive and can throw ArgumentCountError. Write printf("%s", $userInput) instead.
  2. Forgetting to escape a percent sign. A literal percent needs %%. A single % begins a placeholder.
  3. Expecting a string back. printf() returns the length, not the text. Reach for sprintf() when you want to store, return or escape the result.
  4. Supplying too few arguments. Every placeholder needs a value, except %%.
  5. Escaping $ incorrectly. In double-quoted strings %1$s can be interpreted as a variable. Use %1\$s or single quotes.
  6. Rounding surprises. %.2f rounds for display only. It does not change the stored value and cannot fix floating-point representation issues.
  • sprintf() returns the formatted string instead of printing it.
  • vprintf() and vsprintf() take the values as an array.
  • fprintf() and vfprintf() write to a stream.
  • number_format() groups thousands and chooses separators.
  • print and echo output strings without formatting.
  • sscanf() parses a string according to a format, the reverse direction.

Recap

printf() prints a template filled with formatted values and returns the number of characters it printed. Learn the placeholder shape %[argnum$][flags][width][.precision]specifier, escape literal percent signs as %%, never use untrusted input as the template, and switch to sprintf() when you need the formatted text as a value.

Tested examples

Output and return value
<?php
$length = printf("%s has %d items\n", "Cart", 3);
echo $length, "\n";
Output
Cart has 3 items
17
Aligned columns
<?php
$rows = [["Pen", 1.5, 3], ["Notebook", 12.25, 10]];
foreach ($rows as [$name, $price, $qty]) {
    printf("%-10s|%8.2f|%03d\n", $name, $price, $qty);
}
Output
Pen       |    1.50|003
Notebook  |   12.25|010
Argument numbers, literal percent, padding and hex
<?php
printf("%2\$s scored %1\$d%% (%3\$s)\n", 87, "Ana", "pass");
printf("#%02X%02X%02X\n", 255, 128, 0);
printf("[%'*8s]\n", "php");
printf("[%5.1s]\n", "hello");
Output
Ana scored 87% (pass)
#FF8000
[*****php]
[    h]