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

时间:2009-09-06 20:09:38

标签: php printf

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

看看下面的例子。

为什么要用这个:

$output = sprintf("Here is the result: %s for this date %s", $result, $date);

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

$output = 'Here is the result: ' .$result. ' for this date ' .$date;

我在这里错过了什么吗?

24 个答案:

答案 0 :(得分:124)

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

例如,指定数字格式(十六进制,十进制,八进制),小数位数,填充等。谷歌的printf,你会发现很多例子。 wikipedia article on printf应该让你开始。

答案 1 :(得分: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'

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

答案 2 :(得分:46)

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

示例:

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

sprintf('I have a %s %s', $color, $item);

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

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

sprintf('J\'ai un %2$s %1$s', $color, $item);

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

实际上,您使用gettext来存储本地化字符串,但您明白了。


答案 3 :(得分:36)

翻译更容易。

echo _('Here is the result: ') . $result . _(' for this date ') . $date;

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

  • 结果如下:
  • 此日期

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

现在,如果你有

echo sprintf(_("Here is the result: %s for this date %s"), $result, $date);

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

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

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

答案 4 :(得分:16)

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

例如,您的网站会在页面顶部显示“欢迎回[[用户]]”。作为程序员,您不知道或关心 UI用户将如何编写 - 您只需知道用户名将显示在消息中的某个位置。

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

Lang文件(EN_US):

...
$lang['welcome_message'] = 'Welcome back %s';
...

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

sprintf($lang['welcome_message'], $user->name())

答案 5 :(得分: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."

<强> 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."

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

当然,您可以编写自己的函数来执行此替换,毫无疑问,即使性能稍有提高,但更快(假设您有一个类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));

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

答案 6 :(得分: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);

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

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

答案 7 :(得分:6)

使用sprintf()格式化字符串会更清晰,更安全。

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

它还有助于处理浮点数,您可以明确指定数字精度(例如%d),这可以避免使用转换函数。

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

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

例如,请参阅下面的real example

sprintf()

或者一些简单的例子,例如$insert .= "('".$tr[0]."','".$tr[0]."','".$tr[0]."','".$tr[0]."'),";

'1','2','3','4'

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

print "foo: '" . $a . "','" . $b . "'; bar: '" . $c . "','" . $d . "'" . "\n";

其中printf("foo: '%d','%d'; bar: '%d','%d'\n", $a, $b, $c, $d); 等同于printf(),但它输出格式化的字符串而不是将其返回(变量)。

哪个更具可读性?

答案 8 :(得分:4)

即使我有同样的事情,除非我最近使用它。当您根据用户输入生成文档时,这将非常方便。

"<p>Some big paragraph ".$a["name"]." again have tot ake care of space and stuff .". $a["age"]. "also would be hard to keep track of punctuations and stuff in a really ".$a["token"]. paragarapoh.";

可以轻松写成

sprintf("Some big paragraph %s. Again have to take care of space and stuff.%s also wouldnt be hard to keep track of punctuations and stuff in a really %s paragraph",$a,$b,$c);

答案 9 :(得分:4)

此:

"<p>Some big paragraph ".$a["name"]." again have to take care of space and stuff .". $a["age"]. "also would be hard to keep track of punctuations and stuff in a really ".$a["token"]. paragraph.";

也可写:

"<p>Some big paragraph {$a['name']} again have to take care of space and stuff .{$a['age']} also would be hard to keep track of punctuations and stuff in a really {$a['token']} paragraph.";

在我看来,阅读更清楚,但我可以看到本地化或格式化的用途。

答案 10 :(得分:3)

我通常使用sprintf来确保来自用户输入的id是一个整数,例如:

// is better use prepared statements, but this is practical sometimes
$query = sprintf("SELECT * from articles where id = %d;",$_GET['article_id']);

还用于做基本模板(用于html邮件或其他东西),因此您可以在许多地方重复使用模板:

$mail_body = "Hello %s, ...";
$oneMail = sprintf($mail_body, "Victor");
$anotherMail = sprintf($mail_body, "Juan");

格式化不同表示形式的数字(八进制,控制小数位等)非常有用。

答案 11 :(得分:3)

有时我会得到这样的东西,我认为这更容易阅读:

$fileName = sprintf('thumb_%s.%s', 
                    $fileId,
                    $fileInfo['extension']);

答案 12 :(得分:3)

define('TEXT_MESSAGE', 'The variable "%s" is in the middle!');

sprintf(TEXT_MESSAGE, "Var1");
sprintf(TEXT_MESSAGE, "Var2");
sprintf(TEXT_MESSAGE, "Var3");

答案 13 :(得分:3)

  1. 如果您使用过C / C ++,那么您将习惯使用sprintf函数。

  2. 第二行很可能效率较低。 Echo被设计为输出命令,而sprintf被设计为执行字符串标记替换。我不是PHP人员,但我怀疑回声涉及更多对象。如果它像Java一样,它会在每次向列表添加内容时创建一个新字符串,因此最终会创建4个字符串。

答案 14 :(得分:3)

在格式化使用数字的字符串时,

sprintf特别有用。例如,

$oranges = -2.34;
echo sprintf("There are %d oranges in the basket", $oranges);

Output: There are -2 oranges in the basket

橙色被格式化为整数(-2),但如果使用%u作为无符号值,则会将其包围为正数。为了避免这种行为,我使用绝对函数abs()将数字舍入为零,如下所示:

$oranges = -5.67;
echo sprintf("There are %d oranges in the basket", abs($oranges));

Output: There are 5 oranges in the basket

最终结果是一个具有高可读性,逻辑结构,清晰格式以及根据需要添加其他变量的灵活性的语句。随着变量数量的增加以及操纵这些变量的函数的组合,其好处变得更加明显。作为最后一个例子:

$oranges = -3.14;
$apples = 1.5;
echo sprintf("There are %d oranges and %d apples", abs($oranges), abs($apples));

Output: There are 3 oranges and 4 apples

sprintf语句的左侧清楚地表达了字符串和期望值的类型,而右侧清楚地表达了使用的变量以及它们的操作方式。

答案 15 :(得分:3)

嗯,sprintf具有我们所知的许多功能 如下例子:

几个月前,我需要将秒转换为小时:分钟:秒格式 就像$t = 494050 //seconds我打算像137 h 14 m 10 s一样打印所以我想出了php函数springf()我只需要在$t中保持秒数,echo sprintf("%02d h %s%02d m %s%02d s", floor($t/3600), $f, ($t/60)%60, $f, $t%60);给我137 h 14 m 10 s 1}}

如果我们知道如何使用它,那么sprintf()函数非常有用。

答案 16 :(得分:3)

有些典型案例需要您对输出格式进行更精确的控制。例如,确保特定值具有填充到前面的特定数量的空间(取决于其长度),或者以特定的精确格式输出数字,这可能是棘手的。

有很多例子in the PHP manual

你的“更容易写”的例子也是如此。虽然回声可能更容易编写,但sprintf更容易阅读,特别是如果你有很多变量。

使用sprintf或printf的另一个原因可能是您希望让用户定义某些值的输出格式 - 您可以安全地允许他们定义sprintf兼容的输出格式。

哦,你的例子实际上是错误的一部分。 sprintf会返回字符串,但echo没有 - echo会立即输出该字符串并且不返回任何内容,而sprintf只会返回该字符串。

答案 17 :(得分:2)

在普通级联上使用sprintf()函数的优点是可以对要连接的变量应用不同类型的格式。

在你的情况下,你有

$output = sprintf("Here is the result: %s for this date %s", $result, $date);

$output = 'Here is the result: ' .$result. ' for this date ' .$date;

我们来看$result = 'passed'; date = '23rd';

使用普通连接只能获得输出:

Here is the result: passed for this date 23rd

但是,如果您使用sprintf(),则可以获得修改后的输出,例如:

$output = sprintf('Here is the result: %.4s for this date %.2s',$result,$date);
echo $output;

输出:

Here is the result: pass for this date 23

答案 18 :(得分:2)

该参数与使用模板的参数相同。您需要将Textsleev与实际变量值分开。除了sprintf的额外功能,我们提到它只是一种风格的东西。

答案 19 :(得分:2)

使用sprintf的一个非常好的用例是输出填充的数字格式,以及在字符串中混合使用不同类型时。在许多情况下可以更容易阅读,并且可以非常简单地打印同一变量的不同表示,尤其是数字变量。

答案 20 :(得分:1)

printf()printf()非常相似。如果您详细了解sprintf(),那么vsprintf()甚至sprintf()并不是很难理解。

printf()printf("Hello %s", "world"); // "Hello world" sprintf("Hello %s", "world"); // does not display anything echo sprintf("Hello %s", "world"); // "Hello world" $a = sprintf("Hello %s", "world"); // does not display anything echo $a;// "Hello world" 的不同之处之一是,您将需要声明一个变量以捕获函数的输出,因为它不会直接打印/回显任何内容。让我们看下面的代码片段:

dic1 = {'a':10,'b':2}
dic2 = {'a':20,'b':3}
dic3 = {'a':30,'c':'batman'}

pd.DataFrame(data=[dic1,dic2,dic3])

希望有帮助。

答案 21 :(得分:0)

一个“输出”,另一个“返回”,这是主要区别之一。

printf()输出

sprintf()返回

答案 22 :(得分:0)

在循环中使用sprintf时必须小心:

$a = 'Anton';
$b = 'Bert';
$c = 'Corni';
$d = 'Dora';
$e = 'Emiel';
$f = 'Falk';
$loops = 10000000;

$time = microtime(true);

for ($i = 0; $i < $loops; $i++)
{
    $test = $a . $b . $c . $d . $e . $f;
}

$concatTime = microtime(true) - $time;

$time = microtime(true);

for ($i = 0; $i < $loops; $i++)
{
    $test = "$a $b $c $d $e $f";
}

$concat2Time = microtime(true) - $time;

$time = microtime(true);

for ($i = 0; $i < $loops; $i++)
{
    $test = sprintf('%s %s %s %s %s %s', $a, $b, $c, $d, $e, $f);
}

$sprintfTime = microtime(true) - $time;

echo 'Loops: ' . $loops . '<br>';
echo '\'$a . $b . $c . $d . $e . $f\'' . ' needs ' . $concatTime  . 's<br>';
echo '"$a $b $c $d $e $f"' . ' needs ' . $concat2Time  . 's<br>';
echo 'sprintf(\'%s %s %s %s %s %s\', $a, $b, $c, $d, $e, $f)' . ' needs ' . $sprintfTime  . 's<br>';

导致以下情况的时间(在使用PHP 7.2的本地计算机上):

环路:10000000

'$ a。 $ b。 $ c。 $ d。 $ e。 $ f'需要1.4507689476013s

“ $ a $ b $ c $ d $ e $ f”需要1.9958319664001s

sprintf('%s%s%s%s%s%s',$ a,$ b,$ c,$ d,$ e,$ f)需要9.1771278381348s

答案 23 :(得分:0)

我将其用于发送给用户或其他“漂亮”功能的消息。例如,如果我知道我将使用用户名。

$name = 'Some dynamic name';

在这种情况下可以使用多个消息。 (即阻止或关注另一个用户)

$messageBlock = 'You have blocked %s from accessing you.';
$messageFollow = 'Following %s is a great idea!';

您可以创建一个对用户执行某些操作的通用函数,并添加此字符串,无论句子的结构如何,它看起来都非常不错。我总是不喜欢仅将字符串附加在一起,并不断使用点符号以及关闭和重新打开字符串以使句子看起来不错。我一开始像大多数粉丝一样,但是当需要操纵多个字符串并且您不想每次都硬编码变量的位置时,这似乎很有用。

想到了,看起来什么更好?

return $messageOne === true ? $name.'. Please use the next example' : 'Hi '.$name.', how are you?'

$message = $messageOne === true ? 'Option one %s' 
: ($messageTwo === true ? 'Option Two %s maybe?' : '%s you can choose from tons of grammatical instances and not have to edit variable placement and strings');

return sprintf($message, $name);

确保这是一个额外的步骤,但是如果您的条件检查执行了许多其他功能性的操作,那么引号和附加项就会开始妨碍功能性编码。