Why use sprintf function in PHP?
我正在尝试学习有关PHP函数sprintf()的更多信息,但由于我仍然感到困惑,php.net并没有太大帮助,您为什么要使用它?
看下面我的例子。
为什么使用这个:
1 |
当这样做相同并且更容易编写IMO时:
1 | $output = 'Here is the result: ' .$result. ' for this date ' .$date; |
我在这里想念什么吗?
例如,指定数字格式(十六进制,十进制,八进制),小数位数,填充等。 Google for printf,您会发现很多例子。关于printf的维基百科文章应该可以帮助您入门。
sprintf有很多用例,但是我使用它们的一种方式是通过在数据库中存储这样的字符串:"你好,我的名字是%s"或在PHP类中作为常量。这样,当我想使用该字符串时,我可以简单地做到这一点:
1 2 3 4 | $name = 'Josh'; // $stringFromDB = 'Hello, My Name is %s'; $greeting = sprintf($stringFromDB, $name); // $greetting = 'Hello, My Name is Josh' |
本质上,它允许代码中的某些分离。如果我在代码中的很多地方都使用" Hello,我的名字是%s",则可以在一个地方将其更改为"%s是我的名字",并且它会自动更新其他所有地方,而不必转到每个实例并四处移动串联。
例:
1 2 3 4 |
但是像法语这样的语言对单词的排序却有所不同:
1 2 3 4 |
(是的,我的法语很烂:我在学校学习德语!)
实际上,您可以使用gettext来存储本地化的字符串,但是您可以理解。
翻译起来更容易。
1 | echo _('Here is the result: ') . $result . _(' for this date ') . $date; |
翻译(gettext)字符串现在是:
- 结果如下:
- 在这个日期
当翻译成其他语言时,这可能是不可能的,或者导致非常奇怪的句子。
现在如果你有
1 |
翻译(gettext)字符串现在为:
- 结果如下:此日期%s中的%s
这更有意义,而且翻译成其他语言要灵活得多。
我发现的最好原因是,它允许您将所有语言字符串放入您的语言文件中,以便人们可以根据需要对其进行翻译和排序-但您仍然知道,无论字符串采用哪种格式-您都希望显示用户名。
例如,您的网站在页面顶部会显示"欢迎回来[[用户]]"。作为程序员,您不知道或不在乎UI家伙将如何编写-您只知道用户名将显示在消息中的某个位置。
因此,您确实可以将消息嵌入代码中,而不必担心该消息的实际含义。
郎文件(EN_US):
1 2 3 | ... $lang['welcome_message'] = 'Welcome back %s'; ... |
然后,您可以在实际的php代码中使用此语言,以任何语言支持任何类型的消息。
1 |
why would you want to use it?
当使用(外部)语言字符串源时,它非常有用。如果在给定的多语言字符串中需要固定数量的变量,则只需知道正确的顺序即可:
en.txt
1 2 3 | 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
1 2 3 | 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." |
插入的变量甚至不必跨多种语言开头或结尾,只需要它们的顺序即可。
当然,您可以编写自己的函数来执行此替换,即使性能有所提高,但无疑要快得多(假设您有一个类
1 2 3 4 5 6 7 8 9 10 11 12 13 | /** * 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)); |
它还具有
- 浮点数输出精度,或
- 用前导零填充整数。
如前所述,它允许格式化输入数据。例如,强制使用2dp,4位数字等。这对于构建MySQL查询字符串非常有用。
另一个优点是,它允许您将字符串的布局与正在馈入其中的数据分开,就像在参数中馈入一样。例如,对于MySQL查询:
1 2 3 4 | // 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等时。
编辑:出于安全原因,在使用上述技术时,必须使用
使用sprintf()格式化字符串更干净,更安全。
例如,当您处理输入变量时,它可以通过预先指定期望的格式来防止意外的意外发生(例如,您期望字符串[
这也有助于处理浮点数,您可以显式指定位数精度(例如
另一个优点是,大多数主要的编程语言都有自己的
总而言之,使用好习惯是为了使代码更简洁,可读性更好。
例如,请参见下面的实际示例:
1 | $insert .="('".$tr[0]."','".$tr[0]."','".$tr[0]."','".$tr[0]."'),"; |
或一些简单的例子打印
1 2 | print"foo: '" . $a ."','" . $b ."'; bar: '" . $c ."','" . $d ."'" ." "; |
并使用格式化的字符串打印:
1 2 |
其中
哪个更易读?
除非我最近使用过,否则即使我也一样。当您根据用户输入生成文档时,这将很方便。
1 2 | "<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."; |
可以很容易地写成
1 | 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); |
这个:
1 2 | "<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."; |
也可以写成:
1 2 | "<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."; |
我认为这更容易阅读,但是我可以看到它用于本地化或格式化。
在某些典型情况下,您需要对输出格式进行更精确的控制。例如,要确保一个特定值的长度取决于它的长度,或者确保以特定的精确格式输出一个数字,这可能很棘手。
PHP手册中有很多示例
还有示例"易于编写"的内容。尽管回声可能更易于编写,但sprintf却更易于阅读,尤其是在您有很多变量的情况下。
使用sprintf或printf的另一个原因可能是您想让用户定义某个值的输出格式-您可以放心地允许他们定义sprintf兼容的输出格式。
哦,您的示例实际上是错误的。
如果您使用过C / C ++,那么您将习惯于sprintf函数。
第二行很有可能效率较低。 Echo被设计为输出命令,而sprintf被设计为进行字符串令牌替换。我不是PHP人士,但我怀疑回声涉及更多对象。如果它的行为类似于Java,则每次将新内容添加到列表中时都会创建一个新字符串,因此最终将创建4个字符串。
有时我会得到这样的东西,我认为它更容易阅读:
1 2 3 |
我通常使用sprintf来确保来自用户输入的id是整数,例如:
1 2 | // is better use prepared statements, but this is practical sometimes $query = sprintf("SELECT * from articles where id = %d;",$_GET['article_id']); |
也用于做基本模板(用于html邮件或其他东西),因此您可以在许多地方重复使用模板:
1 2 3 |
将数字格式化为不同的表示形式(八进制,控制小数位等)也非常有用。
1 2 3 4 5 |
sprintf在格式化使用数字的字符串时特别有用。例如,
1 2 3 4 | $oranges = -2.34; echo sprintf("There are %d oranges in the basket", $oranges); Output: There are -2 oranges in the basket |
桔子的格式为整数(-2),但是如果将%u用作无符号值,则桔子将环绕成正数。为了避免这种行为,我使用绝对函数abs()将数字四舍五入为零,如下所示:
1 2 3 4 |
最终结果是一条语句具有很高的可读性,逻辑结构,清晰的格式,并且可以根据需要灵活地添加其他变量。随着变量数量的增加以及与操纵这些变量的功能的结合,收益变得更加明显。最后一个例子:
1 2 3 4 5 |
sprintf语句的左侧清楚地表示了字符串和期望值的类型,而右侧则清楚地表示了所使用的变量以及如何对其进行操作。
好吧,
一个例子如下:
几个月前,我需要将秒转换为小时:分钟:秒格式
像
如果我们知道如何使用sprintf()函数,它将非常有用。
使用sprintf的一个非常好的用例是输出带数字的填充格式,以及在字符串中混合使用不同类型时。在许多情况下,它可能更易于阅读,并且使打印同一变量的不同表示形式(尤其是数字表示形式)变得非常简单。
在普通的串联上使用sprintf()函数的优点是,可以对要串联的变量应用不同类型的格式。
就你而言
1 |
和
1 | $output = 'Here is the result: ' .$result. ' for this date ' .$date; |
让我们以
使用普通的串联,您只能得到输出:
1 |
但是,如果使用
1 2 |
输出:
1 |
该参数与使用模板的参数相同。您需要将Textsleev与实际变量值分开。除了我们提到的sprintf的其他功能之外,这还只是一种样式。
1 2 3 4 5 6 7 8 9 |
希望能有所帮助。
我将其用于发送给用户或其他"漂亮"功能的消息。例如,如果我知道我将使用用户名。
1 | $name = 'Some dynamic name'; |
并在这种情况下使用多个消息。 (即阻止或关注另一个用户)
1 2 | $messageBlock = 'You have blocked %s from accessing you.'; $messageFollow = 'Following %s is a great idea!'; |
您可以创建一个对用户执行某些操作的通用函数,并添加此字符串,无论句子的结构如何,它看起来都非常不错。我总是不喜欢仅将字符串附加在一起,并不断使用点符号以及关闭和重新打开字符串以使句子看起来不错。我一开始像大多数粉丝一样,但是当需要操纵多个字符串并且您不想每次都硬编码变量的位置时,这似乎很有用。
想一想,看起来更好的是什么?
1 | return $messageOne === true ? $name.'. Please use the next example' : 'Hi '.$name.', how are you?' |
要么
1 2 3 4 | $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); |
当然,这是一个额外的步骤,但是如果您的条件检查执行了许多其他功能操作,那么引号和附加内容就会开始妨碍功能编码的方式。
一个"输出",另一个"返回",这是主要区别之一。
在循环中使用sprintf时必须小心:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | $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 . ''; echo '\'$a . $b . $c . $d . $e . $f\'' . ' needs ' . $concatTime . 's'; echo '"$a $b $c $d $e $f"' . ' needs ' . $concat2Time . 's'; echo 'sprintf(\'%s %s %s %s %s %s\', $a, $b, $c, $d, $e, $f)' . ' needs ' . $sprintfTime . 's'; |
这导致以下情况(在我的本地计算机上使用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