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

我想了解更多关于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; 

我在这里错过了什么?

sprintf具有原始printf的所有格式化function,这意味着您可以做的不仅仅是在string中插入variables值。

例如,指定数字格式(hex,十进制,八进制),小数点数,填充和更多。 谷歌的printf,你会发现很多的例子。 关于printf的wikipedia文章应该让你开始。

对于sprintf有许多用例,但是我使用它们的一种方法是通过在数据库中存储一个string:“Hello,My Name是%s”或者在PHP类中存储一个常量。 这样,当我想使用该string,我可以简单地做到这一点:

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

从本质上讲,它允许在代码中分离。 如果我在代码中的许多地方使用“你好,我的名字是%s”,我可以在一个地方把它改成'%s是我的名字',而且它自动地更新到其他地方,而不必去每个实例并移动级联。

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

例:

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

但是像法国这样的语言用不同的语言来expression:

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

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

实际上,你会使用gettext来存储本地化的string,但是你明白了。


翻译比较容易。

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

翻译(gettext)string现在是:

  • 结果如下:
  • 这个date

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

现在,如果你有

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

翻译(gettext)string现在是:

  • 结果如下:%s这个date%s

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

我发现的最好的原因是,它允许你把所有的语言string放在你的语言文件中,人们可以根据需要翻译和sorting – 但是你仍然知道,不pipestring是什么格式 – 你想显示用户名。

例如,您的网站会在页面顶部显示“Welcome back [[User]]”。 作为程序员,您不知道或不在乎 UI用户如何写这些 – 您只知道用户名将会显示在消息的某个地方。

所以你可以embedded消息到你的代码,而不用担心这个消息实际上是什么。

Lang文件(EN_US):

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

那么你可以用任何语言支持任何types的消息,在你的实际php代码中使用这个。

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

如前所述,它允许input数据的格式化。 例如,强制2dp,4位数字等。这对于构buildMySQL查询string非常有用。

另外一个好处是,它可以让你从input的数据中分离string的布局,就像喂食参数一样。 例如,在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()清理所有inputvariables ,以防止MySQL插入攻击。 如果你parsingunsanitisedinput,你的网站和服务器将被黑客入侵 。 (当然,除了你的代码已经完全构build的variables,并保证是安全的。)

你为什么要使用它?

当使用(外部)源语言string时,它certificate非常有用。 如果在给定的多语言string中需要固定数量的variables,则只需要知道正确的顺序:

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

插入的variables甚至不必在多语言的开头或结尾,只有他们的sorting很重要。

当然,你可以编写自己的函数来执行这个replace,毫无疑问,即使有一些小的性能提升,但只要(给你一个类Language来读取语言string)快得多:

 /** * 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的全部function,因此也是用于格式化多种typesvariables的单行程序,例如:

  • 浮点数输出精度 ,还是
  • 用前导零填充整数。

使用sprintf()更清晰和更安全的格式化您的string。

例如,当处理inputvariables时,通过预先指定预期的格式(例如,期望string[ %s ]或数字[ %d ])来防止意外的意外。 这可能有助于防止SQL注入的风险,但是如果string包含引号,则不会阻止。

它也有助于处理浮点数,你可以明确地指定数字精度(例如%.2f ),这样就%.2f使用转换函数。

其他的优点是大多数主要的编程语言都有自己的sprintf() ,所以一旦你熟悉它,使用起来就更加容易了,而不是学习一门新的语言(比如如何连接string或者转换花车)。

总而言之,为了使代码清晰可读,这是一个很好的做法。

例如,看下面的实例 :

 $insert .= "('".$tr[0]."','".$tr[0]."','".$tr[0]."','".$tr[0]."'),"; 

或者打印例如'1','2','3','4'简单示例:

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

并用格式化的string打印:

 printf("foo: '%d','%d'; bar: '%d','%d'\n", $a, $b, $c, $d); 

printf()相当于sprintf() ,但是它输出一个格式化的string,而不是返回(到variables)。

哪个更具可读性?

即使我同样的事情,除非我最近使用它。 当您根据用户input生成文档时,这将会派上用场。

 "<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); 

一些典型的情况是你需要更精确地控制输出格式。 例如,要确保一个特定的值具有特定数量的填充到前面的空间,具体取决于其长度,或者以特定的精确格式输出一个数字。

PHP手册中有很多例子

还有什么来你的例子“更容易写”..虽然回声可能更容易编写,sprintf更容易阅读,尤其是如果你有很多变数。

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

哦,你的例子其实是错误的一部分。 sprintf返回string,但echo不 – echo立即输出它并返回什么,而sprintf只是返回它。

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

  2. 第二条线效率较低的可能性很大。 Echo被devise成一个输出命令,而sprintf被devise来执行string标记replace。 我不是一个PHP的人,但我怀疑有更多的对象与回声有关。 如果它像Java一样行事,那么每当有东西被添加到列表中时,它会创build一个新的string,所以最终会创build4个string。

我通常使用sprintf来确保来自用户input的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"); 

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

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

这个:

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

在我看来这是更清晰的阅读,但我可以看到用于本地化或格式化。

格式化使用数字的string时,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 

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

 $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语句的左侧清楚地表示了string和期望值的types,而右侧清楚地表示了所使用的variables以及它们如何被操纵。

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

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

参数与使用模板的参数是一样的。 你需要将Textsleev与实际的variables值分开。 除了我们提到的sprintf的额外function,这只是一种风格的东西。

使用sprintf的一个非常好的用例是输出填充的数字格式,并且在string中混合不同types时。 在许多情况下阅读起来可能会更容易,并且使得打印同一个variables的不同表示方式变得非常简单,尤其是数字方式。

那么, sprintf有很多function,我们知道一个例子如下:

几个月前,我需要将秒转换为小时:分:秒格式像$t = 494050 //seconds我想打印像137 h 14 m 10 s所以我想出了PHP函数springf()我只是举行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

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

使用sprintf()函数而不是普通的串联有一个好处,就是你可以对要连接的variables应用不同types的格式。

在你的情况下,你有

 $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'; $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