Lesson 36 of 100
Strings15 min5 checksPHP 8.5

Format Values with sprintf

Learn how sprintf builds padded, aligned and fixed-decimal strings from format directives, then write a receipt-line formatter.

01 · THE IDEAREAD → TRY → LEARN

Why format strings exist

Concatenating values with . works, but it gets awkward when you need zero-padded numbers, fixed decimals or aligned columns. sprintf() solves this with a template. The template is ordinary text mixed with conversion specifications, and each specification consumes one argument and turns it into text. The function returns the finished string and does not print anything.

sprintf(string $format, mixed ...$values): string

Anatomy of a specification

Every specification begins with % and follows this shape:

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

Only the % and the specifier are required. Here is what each part does:

  • specifier: the type of conversion. d is a signed integer, s a string, f a float, x lowercase hex, b binary. %% prints a literal percent sign and takes no argument.
  • width: the minimum number of characters in the result. Shorter values are padded; longer values are never cut.
  • flags: - left-justifies, + forces a sign on positive numbers, 0 pads numbers with zeros, and ' followed by a character pads with that character. Spaces are the default padding.
  • precision: a period and a number. For f it is the count of digits after the decimal point (6 by default). For s it is a maximum length, so the string is truncated.
  • argnum$: a position such as 2$ that picks which argument to use. It must come right after the %.

Worked example: padded numbers and positions

The first example builds an ISO-style date from integers. %02d means a minimum width of 2, padded with zeros.

Example
<?php
$year = 2005;
$month = 5;
$day = 6;

echo sprintf('%04d-%02d-%02d', $year, $month, $day), PHP_EOL;
Output
2005-05-06

Argument numbering lets the template decide the order. That is useful when a translated sentence needs its pieces in a different sequence, and a numbered placeholder may be reused without passing the value again.

Example
<?php
$num = 5;
$location = 'tree';

$format = 'The %2$s contains %1$04d monkeys';
echo sprintf($format, $num, $location), PHP_EOL;
Output
The tree contains 0005 monkeys

A tour of useful directives

The next example puts many directives side by side. The results go into an array and are encoded as JSON so the padding stays visible inside quotes.

Example
<?php
$parts = [
    sprintf('%.2f', 3.14159),
    sprintf('%8.3f', 2.5),
    sprintf('%-8.1f', 7.5),
    sprintf('%+d', 5),
    sprintf('%.3s', 'abcdef'),
    sprintf("%'*8s", 'php'),
    sprintf('%x', 255),
    sprintf('%b', 5),
    sprintf('%5.1f%%', 45.5),
];

echo json_encode($parts, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), PHP_EOL;
Output
["3.14","   2.500","7.5     ","+5","abc","*****php","ff","101"," 45.5%"]

Read the results carefully. %8.3f makes eight characters with three decimals, right-aligned. %-8.1f is left-aligned, so its padding appears on the right. %.3s cuts a string to three characters, and %'*8s pads with asterisks.

Things to watch

  • Too few arguments throw ArgumentCountError in PHP 8. A negative width or precision throws ValueError.
  • Width counts bytes, not visible characters. For multibyte text, padding with s can look wrong. Stick to ASCII here.
  • f is locale aware, F is not. Use F when a decimal point must be a period no matter what locale is set.
  • Width is a minimum. %02d applied to 100 gives 100, not 10.
  • Rounding of floats follows binary representation, so choose test values that are exactly representable, such as 4.5, when you need predictable output.
  • Type coercion: %d converts its argument to an integer, so a float like 9.99 would lose its fraction. Use %f for decimals.

Exercise contract

Write formatReceiptLine(string $name, int $quantity, float $price): string. It must return one fixed-width line made of four parts:

  1. The name, left-justified in exactly 8 characters, truncated if longer.
  2. One space, then x and the quantity padded with zeros to at least 2 digits.
  3. One space, then the price with exactly two decimals, right-aligned in a width of 7.

For example, Tea, 2 and 4.5 produce Tea x02 4.50. A quantity of 100 keeps all its digits, and a name like Chocolate is cut to Chocolat. Only one sprintf() format string is needed. Build it from the pieces described above.

Recap

A format string is a template of literal text plus % specifications. Width sets a minimum size, flags choose alignment and padding, precision controls decimals or string length, and argnum$ selects arguments by position. Test your formats with values that are exactly representable so the output is predictable.

Before you start

Functions · Arrays · Types

You’ll practice
  • Build deterministic padded and decimal-formatted strings
  • Implement and test a deterministic PHP 8.4 function
Your task

Make formatReceiptLine() pass all 5 checks. Run your code as often as you like, then check your answer.

exercise.phpSaved in this browserPHP 8.5
CONSOLE & CHECKS● Ready

Ready when you are

Your output will appear here.
Make it work. Then make it pass.

PHP loads on your first run. Each check starts fresh. Your code stays in this browser; clearing site data removes your progress. A check or the task looks wrong? Report a problem with this exercise.