为什么在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
只是返回它。
-
如果您使用过C / C ++,那么您将习惯于sprintf函数。
-
第二条线效率较低的可能性很大。 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