`printf()` / `sprintf()` 是 PHP 格式化字串的核心函數,源自 C 語言,功能強大卻常被忽略。本文系統整理所有格式化符號、旗標、寬度、精度控制,並提供實戰範例與對照表。
| 函數 | 輸出目標 | 回傳值 | 用途 |
|---|---|---|---|
| printf() | 直接輸出 (echo) | 輸出字串長度 | 直接顯示 |
| sprintf() | 回傳字串 | 格式化後字串 | 儲存/進一步處理 |
| vprintf() | 直接輸出 | 長度 | 陣列參數版 printf |
| vsprintf() | 回傳字串 | 字串 | 陣列參數版 sprintf |
| fprintf() | 寫入檔案資源 | 長度 | 日誌/檔案輸出 |
| vfprintf() | 寫入檔案 | 長度 | 陣列參數版 fprintf |
%[旗標][寬度][.精度]類型 類型: %% - 字面 % 符號 %b - 二進位整數 %c - ASCII 字元 %d - 有號十進位整數 %e - 科學記號 (小寫 e) 1.2e+2 %E - 科學記號 (大寫 E) 1.2E+2 %f - 浮點數 (依 locale) %F - 浮點數 (不依 locale) %g - %e 或 %f 較短者 %G - %E 或 %f 較短者 %o - 八進位整數 %s - 字串 %u - 無號十進位整數 %x - 十六進位 (小寫) %X - 十六進位 (大寫) 旗標 (順序固定): + - 強制顯示正負號 (空格) - 正數前加空格 0 - 左側補 0 (而非空格) - - 靠左對齊 (預設靠右) 'x - 自訂填充字元 (單引號 + 字元) 寬度: 數字,最小欄位寬度 精度: .數字,小數位數或字串最大長度
$n = 1234.5678;
printf("整數: %d\n", $n); // 1234
printf("浮點: %.2f\n", $n); // 1234.57 (四捨五入)
printf("科學: %e\n", $n); // 1.234568e+3
printf("十六進位: %x\n", 255); // ff
printf("八進位: %o\n", 255); // 377
printf("二進位: %b\n", 10); // 1010
printf("正負號: %+d / %+d\n", 10, -5); // +10 / -5
printf("補零: %08d\n", 42); // 00000042
printf("靠左: %-10sEND\n", 'hi'); // hi END
$str = 'Hello World';
printf("[%s]\n", $str); // [Hello World]
printf("[%20s]\n", $str); // [ Hello World] (靠右)
printf("[%-20s]\n", $str); // [Hello World ] (靠左)
printf("[%020s]\n", $str); // [0000000000Hello World] (補零)
printf("[%'#20s]\n", $str); // [#########Hello World] (自訂填充 #)
printf("[%20.8s]\n", $str); // [ Hello Wo] (截取 8 字)
// %位置$ 格式,位置從 1 開始
$name = '張三';
$age = 25;
$city = '台北';
printf("%2\$s 今年 %1\$d 歲,住在 %3\$s\n", $age, $name, $city);
// 輸出:張三 今年 25 歲,住在台北
// 實務:多語系支援
$fmt_en = 'Hello %1$s, you have %2$d messages.';
$fmt_zh = '%1$s 您好,您有 %2$d 則訊息。';
printf($fmt_zh, '用戶', 5); // 用戶 您好,您有 5 則訊息。
| 場景 | 程式碼 | 輸出 |
|---|---|---|
| 金額顯示 | `printf('NT$ %0.2f', 1234.5);` | NT$ 1234.50 |
| 進度條 | `printf('[%-50s] %d%%', str_repeat('=', $p/2), $p);` | [================== ] 40% |
| 表格對齊 | `printf('| %-20s | %10.2f | %5d |\n', $name, $price, $qty);` | | 商品名稱 | 1234.56 | 10 | |
| 日期格式化 | `printf('%04d-%02d-%02d', $y, $m, $d);` | 2024-01-15 |
| 記憶體單位 | `printf('%.2f MB', $bytes/1024/1024);` | 128.50 MB |
| 色碼轉換 | `printf('#%02X%02X%02X', $r, $g, $b);` | #FF8000 |
// 定義模板常數
const SQL_INSERT_LOG = "INSERT INTO logs (level, message, context, created_at) VALUES ('%s', '%s', '%s', NOW())";
const API_RESPONSE = '{"code":%d,"msg":"%s","data":%s}';
// 使用
$sql = sprintf(SQL_INSERT_LOG, 'ERROR', $msg, json_encode($ctx));
$json = sprintf(API_RESPONSE, 200, 'success', json_encode($data));
// 多語系模板
$templates = [
'zh_TW' => '親愛的 %1$s,您的訂單 %2$s 已 %3$s。',
'en_US' => 'Dear %1$s, your order %2$s has been %3$s.',
];
$msg = sprintf($templates[$lang] ?? $templates['zh_TW'], $name, $orderNo, $status);
$iterations = 100000; $str = 'Hello %s, number %d'; // sprintf $start = microtime(true); for ($i=0; $i<$iterations; $i++) sprintf($str, 'World', $i); echo 'sprintf: ' . (microtime(true)-$start) . "s\n"; // 字串串接 $start = microtime(true); for ($i=0; $i<$iterations; $i++) 'Hello World, number ' . $i; echo 'concat: ' . (microtime(true)-$start) . "s\n"; // 通常 sprintf 比串接慢 2-3 倍,但在複雜格式下可讀性高得多
`printf()`/`sprintf()` 是格式化輸出的標準工具,掌握類型符號、旗標/寬度/精度、位置參數三大核心,即可應付 99% 的格式化需求。建議:簡單串接用 `.`,複雜格式用 `sprintf()`,多語系/模板化必用 `sprintf()`。