在 PHP 中,sprintf 函数是一个强大的字符串格式化工具,能够将变量以指定格式插入字符串中。例如:
$name = "Alice";
$age = 30;
echo sprintf("我的名字是 %s,今年 %d 岁。", $name, $age);
输出为:
我的名字是 Alice,今年 30 岁。
虽然 sprintf 已经非常实用,但有时我们可能希望更灵活地控制格式化方式,或者在某些框架或环境下实现一个“轻量版”或者“可定制版”的格式化函数。本文将介绍如何用 PHP 自定义一个类似 sprintf 的格式化函数。
我们希望实现一个函数 my_sprintf($template, $args),其支持以下功能:
替换占位符,如 %s、%d;
支持顺序传参或数组传参;
保持良好的可读性与可维护性。
我们从一个简单的实现开始,仅支持 %s 和 %d:
function my_sprintf($template, ...$args) {
$argIndex = 0;
$result = preg_replace_callback('/%[sd]/', function($matches) use (&$args, &$argIndex) {
$placeholder = $matches[0];
$value = $args[$argIndex++] ?? '';
if ($placeholder === '%d') {
return intval($value);
} elseif ($placeholder === '%s') {
return strval($value);
} else {
return $placeholder;
}
}, $template);
return $result;
}
echo my_sprintf("欢迎 %s,您有 %d 条新消息。", "Alice", 5);
输出:
欢迎 Alice,您有 5 条新消息。
如果我们想让这个函数也支持将参数以数组形式传入,可以稍作修改:
function my_sprintf_array($template, array $args) {
$argIndex = 0;
$result = preg_replace_callback('/%[sd]/', function($matches) use (&$args, &$argIndex) {
$placeholder = $matches[0];
$value = $args[$argIndex++] ?? '';
return match ($placeholder) {
'%d' => intval($value),
'%s' => strval($value),
default => $placeholder,
};
}, $template);
return $result;
}
echo my_sprintf_array("请访问 https://gitbox.net/user/%s,积分:%d", ["alice", 100]);
输出:
请访问 https://gitbox.net/user/alice,积分:100
我们还可以进一步支持格式如 %05d(宽度为5,左侧补零):
function my_sprintf_extended($template, ...$args) {
$argIndex = 0;
$result = preg_replace_callback('/%0?(\d*)([sd])/', function($matches) use (&$args, &$argIndex) {
$width = (int)($matches[1] ?? 0);
$type = $matches[2];
$value = $args[$argIndex++] ?? '';
if ($type === 'd') {
$formatted = str_pad(intval($value), $width, '0', STR_PAD_LEFT);
} else {
$formatted = strval($value);
}
return $formatted;
}, $template);
return $result;
}
echo my_sprintf_extended("订单号:%05d,用户:%s", 42, "bob");
输出:
订单号:00042,用户:bob
通过上述几个版本的实现,我们可以看到:
自定义格式化函数让我们可以根据业务需要灵活控制;
利用正则表达式结合回调函数,是实现类似 sprintf 的关键;
若需更复杂格式(如浮点、进制、占位顺序等),可继续扩展正则表达式的解析规则。
在实际项目中,这类函数也常用于自定义模板引擎、日志记录系统或 DSL(领域特定语言)开发中,为开发带来更多便利与控制力。
你可以将这个函数封装进自己的工具库中,在类似 https://gitbox.net 这样的项目中使用,提升开发效率。