关于性能,执行以下操作有什么区别:
$message = "The request $request has $n errors";
和
$message = sprintf('The request %s has %d errors', $request, $n);
在 PHP 中?
我会说调用函数涉及更多的东西,但我不知道 PHP 在幕后做了什么来扩展变量名称。
谢谢!
关于性能,执行以下操作有什么区别:
$message = "The request $request has $n errors";
和
$message = sprintf('The request %s has %d errors', $request, $n);
在 PHP 中?
我会说调用函数涉及更多的东西,但我不知道 PHP 在幕后做了什么来扩展变量名称。
谢谢!
不要紧。
任何性能提升都将是如此微不足道,以至于您只会在 10000 或 100000 次迭代中看到它(作为百分之几秒的改进)——即使如此。
有关具体数字,请参阅此基准。您可以看到它必须使用 100,000 次函数调用生成 1MB+ 的数据才能在数百毫秒内实现可测量的差异。几乎不是现实生活中的情况。即使是最慢的方法(“sprintf() with positional params”)也只需要 0.00456 毫秒,而最快的方法是 0.00282 毫秒。对于任何需要 100,000 次字符串输出调用的操作,您将有其他因素(例如网络流量)比通过优化可以节省的 100 毫秒慢一个数量级。
使用任何使您的代码对您和其他人来说最易读和可维护的东西。对我个人而言,该sprintf()
方法是一个巧妙的想法——我必须考虑自己开始使用它。
在所有情况下,第二个都不会更快,因为您提供了一个双引号字符串,它也必须解析为变量。如果要进行微优化,正确的方法是:
$message = sprintf('The request %s has %d errors', $request, $n);
尽管如此,我相信秒数会变慢(正如@Pekka 指出的差异实际上并不重要),因为函数调用、解析字符串、转换值等的开销。但是请注意,2 行代码不是等效,因为在第二种情况下 $n 被转换为整数。如果 $n 是“无错误”,那么第一行将输出:
The request $request has no error errors
而第二个将输出:
The request $request has 0 errors
此处进行了关于“变量扩展与 sprintf”的性能分析。
正如@pekka 所说,“使您的代码对您和其他人来说最具可读性和可维护性”。当性能增益“低”(~小于两倍)时,忽略它。
总结基准:PHP 针对双引号和 Heredoc 分辨率进行了优化。尊重平均时间的百分比,仅使用计算很长的字符串,
请注意,只有 sprintf 执行一些格式化任务(请参阅基准的 '%s%s%d%s%f%s'),并且正如@Darhazer 所示,它对输出有一些影响。更好的测试是两个基准测试,一个只比较连接时间('%s' 格式化程序),其他包括格式化过程 - 例如 '%3d%2.2f' 和在将变量扩展为双引号之前的等效功能......还有更多使用短模板字符串的基准组合。
正如基准所显示的那样,它的主要优点sprintf
是非常低成本的格式化程序(!)。对于通用模板,我建议使用vsprintf函数。
双引号(和heredoc)的主要优点是一些性能;与 sprintf 的位置标记相比,标称占位符的一些可读性和可维护性随着参数的数量(在 1 之后)而增长。
索引占位符的使用是 sprintf 可维护性的一半。
注意:不要使用单引号连接,只有在确实需要时。请记住,PHP 启用了安全语法,例如"Hello {$user}_my_brother!"
和引用,例如"Hello {$this->name}!"
.
我很惊讶,但对于 PHP 7.*,“$variables replacement”是最快的方法:
$message = "The request {$request} has {$n} errors";
您可以简单地自己证明:
$request = "XYZ";
$n = "0";
$mtime = microtime(true);
for ($i = 0; $i < 1000000; $i++) {
$message = "The request {$request} has {$n} errors";
}
$ctime = microtime(true);
echo '
"variable $replacement timing": '. ($ctime-$mtime);
$request = "XYZ";
$n = "0";
$mtime = microtime(true);
for ($i = 0; $i < 1000000; $i++) {
$message = 'The request '.$request.' has '.$n.' errors';
}
$ctime = microtime(true);
echo '
"concatenation" . $timing: '. ($ctime-$mtime);
$request = "XYZ";
$n = "0";
$mtime = microtime(true);
for ($i = 0; $i < 1000000; $i++) {
$message = sprintf('The request %s has %d errors', $request, $n);
}
$ctime = microtime(true);
echo '
sprintf("%s", $timing): '. ($ctime-$mtime);
PHP 7.3.5的结果:
“可变$更换时间”:0.091434955596924
“串联”。$计时:0.11175799369812
sprintf("%s", $timing): 0.17482495307922
可能您已经找到了诸如“使用 sprintf 而不是双引号中包含的变量,它的速度大约快 10 倍”之类的建议。有哪些好的 PHP 性能提示?
我知道这是事实,但总有一天。即在PHP 5.2.*之前
以下是当时PHP 5.1.6的示例:
“可变$更换时间”:0.67681694030762
“串联”。$计时:0.24738907814026
sprintf("%s", $timing): 0.61580610275269
对于将多个字符串变量注入字符串,第一个会更快。
$message = "The request $request has $n errors";
并且对于单次注入,点(。)连接会更快。
$message = 'The request '.$request.' has 0 errors';
用十亿循环进行迭代并找出差异。
例如:
<?php
$request = "XYZ";
$n = "0";
$mtime = microtime(true);
for ($i = 0; $i < 1000000; $i++) {
$message = "The request {$request} has {$n} errors";
}
$ctime = microtime(true);
echo ($ctime-$mtime);
?>
最终,在考虑单个变量赋值的上下文时,第一个是最快的,这可以通过查看各种基准来看到。不过,也许使用核心 PHP 函数的 sprintf 风格可以允许更多可扩展的代码,并针对 opcache 或 apc 等字节码级缓存机制进行更好的优化。换句话说,特定大小的应用程序在使用 sprintf 方法时可以使用更少的代码。您需要缓存到 RAM 中的代码越少,用于其他事情或更多脚本的 RAM 就越多。但是,这仅在您的脚本无法使用评估正确放入 RAM 时才重要。