当前位置: 首页> 最新文章列表> 如何实现类似 sprintf 的自定义格式化函数

如何实现类似 sprintf 的自定义格式化函数

gitbox 2025-04-28

在 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 这样的项目中使用,提升开发效率。