为什么在PHP中使用sprintf函数?

Jas*_*vis 186 php printf

我正在尝试更多地了解PHP函数sprintf()但是php.net对我没有多大帮助,因为我仍然感到困惑,为什么要使用它?

看看我下面的例子.

为什么用这个:

$output = sprintf("Here is the result: %s for this date %s", $result, $date);
Run Code Online (Sandbox Code Playgroud)

如果这样做并且更容易编写IMO:

$output = 'Here is the result: ' .$result. ' for this date ' .$date;
Run Code Online (Sandbox Code Playgroud)

我在这里错过了什么吗?

Isa*_*avo 127

sprintf 具有原始printf的所有格式化功能,这意味着您可以做的不仅仅是在字符串中插入变量值.

例如,指定数字格式(十六进制,十进制,八进制),小数位数,填充等.谷歌的printf,你会发现很多例子.关于printf维基百科文章应该可以帮助您入门.

  • 几年前我为零填充数写了一个很好的函数.在意识到我可以简单地执行`sprintf('%03d',$ num)之前已经使用了很长时间 (45认同)
  • PHP*sprintf具有所有格式化功能*...实际上缺少一个重要的格式,例如`%,8d`以获得正确对齐的8位数和逗号分隔的整数.使用`number_format`在`printf`样式中不太方便. (5认同)
  • @DisgruntledGoat你可以分解那个格式化字符串('%03d')吗?我认为这会非常有帮助.谢谢. (3认同)
  • 您还可以重复和重新排序要显示的参数.例如`sprintf('%2 $ s%1 $ s,我的名字也是%1 $ s.','世界','你好');`导致'Hello World,我的名字也是世界. (3认同)

mac*_*osh 76

sprintf有很多用例,但我使用它的一种方法是存储一个这样的字符串:'Hello,My Name is%s'在数据库中或作为PHP类中的常量.这样,当我想使用该字符串时,我可以简单地这样做:

$name = 'Josh';
// $stringFromDB = 'Hello, My Name is %s';
$greeting = sprintf($stringFromDB, $name);
// $greetting = 'Hello, My Name is Josh'
Run Code Online (Sandbox Code Playgroud)

基本上它允许在代码中进行一些分离.如果我在我的代码中的许多地方使用'Hello,My Name is%s',我可以在一个地方将其更改为'%s是我的名字',并且它可以自动更新到其他地方,而无需转到每个实例并四处移动级联.

  • 这个.现在添加编号参数和翻译:] (8认同)

Ken*_*nan 46

另一个用途sprintf是在本地化应用程序中作为参数,sprintf不必按照它们在格式字符串中出现的顺序.

例:

$color = 'blue';
$item = 'pen';

sprintf('I have a %s %s', $color, $item);
Run Code Online (Sandbox Code Playgroud)

但像法语这样的语言对单词的命令不同:

$color = 'bleu';
$item = 'stylo';

sprintf('J\'ai un %2$s %1$s', $color, $item);
Run Code Online (Sandbox Code Playgroud)

(是的,我的法语很糟糕:我在学校学过德语!)

实际上,您可以使用gettext来存储本地化的字符串,但您会明白这一点.



ras*_*spi 36

翻译更容易.

echo _('Here is the result: ') . $result . _(' for this date ') . $date;
Run Code Online (Sandbox Code Playgroud)

翻译(gettext)字符串现在是:

  • 结果如下:
  • 这个日期

当翻译成其他语言时,它可能是不可能的,或者导致非常奇怪的句子.

现在,如果你有

echo sprintf(_("Here is the result: %s for this date %s"), $result, $date);
Run Code Online (Sandbox Code Playgroud)

翻译(gettext)字符串现在是:

  • 结果如下:此日期%s的%s

这更有意义,而且翻译成其他语言要灵活得多

  • 虽然对于翻译,使用位置说明符可能会更好,在翻译时允许一些额外的灵活性,即:`echo sprintf(_("这是结果:%1 $ s为此日期%2 $ s"),$结果,$ date);`这将允许翻译修改短语,如`对于日期%2 $ s,结果是%1 $ s` (6认同)
  • 我知道这会非常有用+1 (2认同)
  • 即使它们不存在于原始字符串中,您也可以将它们放入翻译中并且它们会起作用。 (2认同)

Xeo*_*oss 16

我找到的最好的理由是,它允许您将所有语言字符串放在您的语言文件中,如果人们可以翻译并根据需要进行排序 - 但您仍然知道无论字符串处于何种格式 - 您希望显示用户名.

例如,您的网站会在页面顶部显示"欢迎回[[用户]]".作为程序员,你不知道或不关心 UI人员将如何编写 - 你只知道用户名将在消息中的某处显示.

因此,您可以将消息嵌入到代码中,而不必担心该消息实际上是什么.

Lang文件(EN_US):

...
$lang['welcome_message'] = 'Welcome back %s';
...
Run Code Online (Sandbox Code Playgroud)

然后,您可以在实际的PHP代码中使用它来支持任何语言的任何类型的消息.

sprintf($lang['welcome_message'], $user->name())
Run Code Online (Sandbox Code Playgroud)


Joh*_*isz 9

你为什么要用呢?

当使用(外部)源语言字符串时,它证明非常有用.如果在给定的多语言字符串中需要固定数量的变量,则只需要知道正确的顺序:

en.txt

not_found    = "%s could not be found."
bad_argument = "Bad arguments for function %s."
bad_arg_no   = "Bad argument %d for function %s."
Run Code Online (Sandbox Code Playgroud)

hu.txt

not_found    = "A keresett eljárás (%s) nem található."
bad_argument = "Érvénytelen paraméterek a(z) %s eljárás hívásakor."
bad_arg_no   = "Érvénytelen %d. paraméter a(z) %s eljárás hívásakor."
Run Code Online (Sandbox Code Playgroud)

插入的变量甚至不必在多种语言的开头或结尾,只有它们的顺序很重要.

当然,您可以编写自己的函数来执行此替换,毫无疑问,即使性能稍有提高,但它只是快得多(假设您有一个类Language来读取语言字符串):

/**
 * throws exception with message($name = "ExampleMethod"):
 *  - using en.txt: ExampleMethod could not be found.
 *  - using hu.txt: A keresett eljárás (ExampleMethod) nem található.
 */
throw new Exception(sprintf(Language::Get('not_found'), $name));

/**
 * throws exception with message ($param_index = 3, $name = "ExampleMethod"):
 *  - using en.txt: Bad argument 3 for function ExampleMethod.
 *  - using hu.txt: Érvénytelen 3. paraméter a(z) ExampleMethod eljárás hívásakor.
 */
throw new Exception(sprintf(Language::Get('bad_arg_no'), $param_index, $name));
Run Code Online (Sandbox Code Playgroud)

它还具有全部功能printf,因此也是用于格式化多种类型变量的单行程序,例如:


Sam*_*hke 8

如上所述,它允许格式化输入数据.例如,强制使用2dp,4位数字等.这对于构建MySQL查询字符串非常有用.

另一个优点是它允许您将字符串的布局与输入数据的数据分开,几乎就像在参数中一样.例如,在MySQL查询的情况下:

// For security, you MUST sanitise ALL user input first, eg:
$username = mysql_real_escape_string($_POST['username']); // etc.
// Now creating the query:
$query = sprintf("INSERT INTO `Users` SET `user`='%s',`password`='%s',`realname`='%s';", $username, $passwd_hash, $realname);
Run Code Online (Sandbox Code Playgroud)

这种方法当然有其他用途,例如将输出打印为HTML等.

编辑:出于安全原因,使用上述技术时,必须mysql_real_escape_string()先使用此方法清理所有输入变量,以防止MySQL插入攻击.如果您解析未经过处理的输入,您的站点和服务器将被黑客入侵.(当然,除了代码完全构造并保证安全的变量之外.)

  • 该代码易受SQL注入攻击.使用占位符,而不是查询插值! (2认同)

ken*_*orb 6

使用sprintf()可以更加清晰,更安全地格式化字符串.

例如,当您处理输入变量时,它会通过提前指定预期格式(例如,您期望字符串[ %s]或数字[ %d])来防止意外惊喜.这可能有助于SQL注入的可能风险,但如果字符串包含引号则不会阻止.

它还有助于处理浮点数,您可以明确指定数字精度(例如%.2f),这使您无需使用转换函数.

其他优点是大多数主要的编程语言都有自己的实现sprintf(),所以一旦你熟悉它,它就会更容易使用,而不是学习一门新语言(比如如何连接字符串或转换浮点数).

总之,使用它是一种更好的做法,以便拥有更清晰,更易读的代码.

例如,请参阅以下真实示例:

$insert .= "('".$tr[0]."','".$tr[0]."','".$tr[0]."','".$tr[0]."'),";
Run Code Online (Sandbox Code Playgroud)

或者打印一些简单的例子'1','2','3','4':

print "foo: '" . $a . "','" . $b . "'; bar: '" . $c . "','" . $d . "'" . "\n";
Run Code Online (Sandbox Code Playgroud)

并使用格式化字符串打印:

printf("foo: '%d','%d'; bar: '%d','%d'\n", $a, $b, $c, $d);
Run Code Online (Sandbox Code Playgroud)

where printf()等于sprintf(),但它输出一个格式化的字符串而不是返回它(到变量).

哪个更具可读性?

  • 我并不反对,但值得一提的是,我在 6-7 年前问过这个问题,现在回想起来,我不记得从那时起我曾经使用过这个!我确实希望有一天能为它找到一个地方,并且相信它有一个地方,但有趣的是,自从多年前问这个问题以来,我就没有使用过它! (2认同)