Signature
vfprintf(resource $stream, string $format, array $values): intPurpose
vfprintf() builds a string from a format template and an array of values, then writes that string to a stream. It is the array-taking sibling of fprintf(). Use it when your values already live in an array, for example a database-style row, a list of report columns or arguments collected at runtime, and you want to send formatted text to a stream without unpacking the array yourself.
Signature
Parameters
$stream: an open, writable stream resource, such as one returned byfopen(). There is no default. In the browser sandbox,php://outputandphp://memoryare convenient in-memory targets.$format: the template. Ordinary characters are copied unchanged. Each conversion specification follows the shape%[argnum$][flags][width][.precision]specifier.$values: the array of values consumed by the conversions, in order, unless anargnum$selects one explicitly.
Format pieces
argnum$picks a value by position, starting at 1, so one value can be reused (%1$s).- Flags include
-(left-justify),+(always show a sign),0(zero padding), a space (space padding, the default) and'followed by a character (custom padding character). - Width is the minimum field size. Precision, written after a period, means decimals for
f,F,eandE, significant digits forg,G,handH, and a maximum length fors. - Common specifiers are
s,d,u,f,F,e,x,X,o,b,cand the literal%%.
Return value and failures
The function returns an int: the length of the string that was written. Since PHP 8.0 it no longer returns false on failure. Problems with the format, such as too few values for the conversions, or an invalid width or precision, now cause an error to be thrown (the manual documents ValueError). Tests that check for such mistakes should catch Throwable rather than test for false.
The stream argument must be a valid resource. If fopen() failed and you pass false, you get a type error instead of formatted output, so check the result of fopen() first.
Example 1: writing a zero-padded date
The first example writes to php://output and shows that the return value counts every written character, including the newline.
$out = fopen('php://output', 'w');
$length = vfprintf($out, "%04d-%02d-%02d\n", [2025, 5, 6]);
fclose($out);
echo $length, "\n";2025-05-06 11
Example 2: reusing values by position
With argnum$, the order in the template does not have to match the order in the array. Here the name is used twice. Single quotes keep PHP from interpreting $s as a variable. The in-memory stream is rewound so the written text can be read back.
$stream = fopen('php://memory', 'w+');
$bytes = vfprintf($stream, '%2$s owes %1$.2f USD (%2$s)', [12.5, 'Ana']);
rewind($stream);
$text = stream_get_contents($stream);
fclose($stream);
echo json_encode(['bytes' => $bytes, 'text' => $text], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);{"bytes":24,"text":"Ana owes 12.50 USD (Ana)"}Example 3: padding, alignment and precision
This row combines left-justification, a fixed float precision and a custom padding character. The '* flag pads with asterisks.
$stream = fopen('php://memory', 'w+');
$length = vfprintf($stream, '%-8s|%6.1f|%\'*5d', ['apple', 3.14159, 42]);
rewind($stream);
$text = stream_get_contents($stream);
fclose($stream);
echo json_encode(['length' => $length, 'text' => $text], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);{"length":21,"text":"apple | 3.1|***42"}Edge cases
- The returned length is measured in bytes, not characters. Width and precision with
salso count bytes, so multibyte text can be padded or cut in the middle of a character. - The
cspecifier ignores padding and width. %%consumes no value, so it does not shift later positions.- The
fspecifier is locale aware, whileFis not. PreferFwhen the output must be stable across environments. - A precision given as a bare period means 0 for that conversion.
- Extra values beyond what the format uses are ignored; missing ones are an error.
- Values are coerced to what the specifier needs, so a numeric string works with
d, and a float passed todis converted to an integer.
Common mistakes
- Using double quotes around
%1$s. PHP then tries to interpolate$s. Use single quotes or escape the dollar sign. - Passing separate arguments instead of an array.
vfprintf($s, $fmt, 1, 2)is wrong; the third argument must be one array. - Forgetting that the stream must be writable. A stream opened with
'r'cannot receive the output. - Reading an in-memory stream without
rewind(). After writing, the pointer is at the end, so the read returns an empty string. - Expecting
falseon failure. Modern PHP throws instead. - Treating the return value as a character count for non-ASCII text.
Related functions
fprintf() takes values as separate arguments. vprintf() prints an array-formatted string to output, and vsprintf() returns it as a string. sprintf() and printf() are the non-array counterparts. number_format() is better for thousands separators.
Recap
vfprintf() formats an array of values with a printf-style template and writes the result to a stream, returning the number of bytes written. Choose it when the arguments are already in an array and the destination is a stream. Use single-quoted templates for positional arguments, rewind in-memory streams before reading, and expect an error rather than false when the format and values do not match.
Tested examples
$out = fopen('php://output', 'w');
$length = vfprintf($out, "%04d-%02d-%02d\n", [2025, 5, 6]);
fclose($out);
echo $length, "\n";
2025-05-06 11
$stream = fopen('php://memory', 'w+');
$bytes = vfprintf($stream, '%2$s owes %1$.2f USD (%2$s)', [12.5, 'Ana']);
rewind($stream);
$text = stream_get_contents($stream);
fclose($stream);
echo json_encode(['bytes' => $bytes, 'text' => $text], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);{"bytes":24,"text":"Ana owes 12.50 USD (Ana)"}
$stream = fopen('php://memory', 'w+');
$length = vfprintf($stream, '%-8s|%6.1f|%\'*5d', ['apple', 3.14159, 42]);
rewind($stream);
$text = stream_get_contents($stream);
fclose($stream);
echo json_encode(['length' => $length, 'text' => $text], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);{"length":21,"text":"apple | 3.1|***42"}