
至于PHP的微优化,通过将双引号替换为单引号,会破坏很多副本,因此重新编写流是很成问题的。 但是我会尽力的。
在本文中,将只有一个基准,如果没有基准,它将是什么,并且主要重点是分析它在内部的排列方式。
免责声明
- 下文所述的大部分程序大部分时间都在纳秒级以下,实际上,它什么也做不了,只不过浪费了这种微优化所浪费的时间。 对于编译时间的“优化”尤其如此。
- 我将削减代码并最大程度地输出,仅保留本质。
- 撰写文章时,我使用了PHP 7.2
必要的入门
在编译阶段 ,双引号的字符串与单引号的字符串的处理方式略有不同。
单引号将被解析为:
statement -> expr -> scalar -> dereferencable_scalar -> T_CONSTANT_ENCAPSED_STRING
因此:
statement -> expr -> scalar -> '"' encaps_list '"' -> , ,
在有关PHP微优化的文章中,经常建议不要使用
print ,因为它比
echo慢。 让我们看看它们如何排序。
解析
echo :
statement -> T_ECHO echo_expr_list -> echo_expr_list -> echo_expr -> expr
解析
打印 :
statement -> expr -> T_PRINT expr -> expr ( )
即 通常,是的,
回声是在较早的步骤中检测到的,应该注意,这一步骤非常困难。
为了避免在本文中再次引起注意,我们将牢记在编译阶段,双引号会丢失单引号,而
打印会丢失
echo 。 另外,请不要忘记,在最坏的情况下,大约是十亿分之一秒。
好吧,以免起床两次。 这是用于编译
print和
echo的diff函数:
1 - void zend_compile_print(znode *result, zend_ast *ast) 1 + void zend_compile_echo(zend_ast *ast) 2 2 { 3 3 zend_op *opline; 4 4 zend_ast *expr_ast = ast->child[0]; 5 5 6 6 znode expr_node; 7 7 zend_compile_expr(&expr_node, expr_ast); 8 8 9 9 opline = zend_emit_op(NULL, ZEND_ECHO, &expr_node, NULL); 10 - opline->extended_value = 1; 11 - 12 - result->op_type = IS_CONST; 13 - ZVAL_LONG(&result->u.constant, 1); 10 + opline->extended_value = 0; 14 11 }
好了,您了解-它们的功能相同,但是
print还会返回一个等于1的常量。我认为,使用
print可以使您永远关闭并忘记它。
简单的线条,没有多余的装饰
字符串
echo 'Some string';
并
echo "Some string";
将几乎完全分为2个(免责声明P2)令牌。
T_ECHO: echo T_ENCAPSED_AND_WHITESPACE/T_CONSTANT_ENCAPSED_STRING: "Some string"
此外,对于单引号,总是存在T_CONSTANT_ENCAPSED_STRING,对于双引号,则总是存在。 如果行中有空格,则为T_ENCAPSED_AND_WHITESPACE。
操作码很容易让人感到耻辱,并且绝对相同:
line
结论
如果要在编译阶段节省几个处理器周期,则对于常量字符串,请使用单引号。
动态线
有4个选项。
echo "Hello $name! Have a nice day!"; echo 'Hello '.$name.'! Have a nice day!'; echo 'Hello ', $name, '! Have a nice day!'; printf ('Hello %s! Have a nice day!', $name);
对于第一种选择:
T_ECHO: echo T_ENCAPSED_AND_WHITESPACE: Hello T_VARIABLE: $name T_ENCAPSED_AND_WHITESPACE: ! Have a nice day!
对于第二个(对于第三个也是如此,只有逗号而不是句点):
T_ECHO: echo T_CONSTANT_ENCAPSED_STRING: 'Hello ' string: . T_VARIABLE: $name string: . T_CONSTANT_ENCAPSED_STRING: '! Have a nice day!'
对于第四:
T_STRING: printf T_CONSTANT_ENCAPSED_STRING: 'Hello %s! Have a nice day!' string: , T_VARIABLE: $name
但是有了操作码,一切都会变得更加有趣。
第一个:
echo "Hello $name! Have a nice day!"; line
第二:
echo 'Hello '.$name.'! Have a nice day!'; line
第三:
echo 'Hello ', $name, '! Have a nice day!'; line
第四名:
printf ('Hello %s! Have a nice day!', $name); line
常识告诉我们,带有printf的选项将在前三个选项中失去速度(特别是由于最后仍然存在相同的ECHO),因此我们将其留给需要格式化的任务,我们将在本文中记不清了。
第三种选择似乎是最快的-连续打印三行,而无需串联,奇怪的ROPE和创建其他变量。 但不是那么简单。 PHP中的print函数当然不是Rocket Science,但绝不是普通的C-shny
fputs 。 谁
在乎 -球从
main / output.c文件中的
php_output_write开始解散。
CONCAT。 这里的一切都很简单-如果需要,我们将参数转换为字符串,并使用快速
memcpy创建新的
zend_string 。 唯一的负面影响是,对于每个操作,如果有很长的串联链接,则将不同的字节从一个地方移到另一个地方将创建新行。
但是有了ROPE_INIT,ROPE_ADD和ROPE_END,一切都变得更加有趣了。 跟随手:
- ROPE_INIT(ext = 3,return =〜3,操作数='Hello +')
我们从三个插槽(扩展名)分配“绳索”,将字符串“ Hello +”(操作数)放入插槽0,然后返回包含“绳索”的临时变量〜3(返回)。 - ROPE_ADD(ext = 1,return =〜3,操作数=〜3,!0)
我们将“ rope”〜3(操作数)的插槽1(ext)放入从变量!0(操作数)获得的字符串“ Vasya”,并返回“ rope”〜3(返回)。 - ROPE_END(ext = 2,return =〜2,操作数=〜3,'%21 + Have + a + nice + day%21')
我们将'%21 + Have + a + nice + day%21'行(操作数)放入插槽2(扩展名)中,然后创建所需大小的zend_string,并使用相同的memcpy依次将所有“ rope”插槽复制到该行中。
另外,值得注意的是,在常量和临时变量的情况下,指向数据的链接将放置在插槽中,并且不会有不必要的复制。
在我看来,非常优雅。 :)
让我们进行基准测试。 作为源数据,我们将文件
zend_vm_execute.h (恕我直言,这将是真的)用于
71000行,并以100种方式打印100次,最小和最大值(每次测量开始10次,选择最常用的选项):
<?php $file = explode("\n", file_get_contents("C:\projects\C\php-src\Zend\zend_vm_execute.h")); $out = []; for ($c = 0; $c < 100; $c++) { $start = microtime(true); ob_start(); $i = 0; foreach ($file as $line) { $i++;
我们衡量什么 | 平均时间(以秒为单位) |
---|
“绳子” | 0.0129 |
几个回声 | 0.0135 |
级联 | 0.0158 |
printf ,为了完整性 | 0.0245 |
结论
- 对于具有简单替换的字符串,突然出现的双引号要比带有串联的单引号更好。 并且使用的线越长,增益越大。
- 以逗号分隔的参数。有许多细微差别。 通过测量,它比连接快,但比“绳索”慢,但是与输入/输出关联的“变量”太多。
结论
对于我而言,很难提出可能需要进行此类微优化的情况。 选择这种方式时,以其他原则为指导更为合理-例如,代码可读性或贵公司采用的编码风格。
就我个人而言,由于vyrviglazny的外观,我不喜欢使用串联方法,尽管在某些情况下它是合理的。
PS:如果这种分析很有趣-让我知道-还有很多事情远非总是一目了然:VS对象数组,foreach VS,而VS for,您可以选择... :)
阅读评论的一些解释
HEREDOC语法和“复杂字符串”(变量在大括号内)是相同的双引号字符串,并且以完全相同的方式进行编译。
PHP与HTML的混合如下:
<?php $name = 'Vasya';?>Hello <?=$name?>! Have a nice day!
这只是连续3个
回声 。