参考:比较PHP的打印和回显
PHP的print
和echo
什么区别?
Stack Overflow有许多关于PHP的print
和echo
关键字用法的问题。
这篇文章的目的是提供关于PHP的print
和echo
关键字的规范参考问题和答案,并比较它们的差异和用例。
为什么两个结构?
关于print和echo的真相是,虽然它们对用户来说是两种截然不同的结构,但如果您深入到基础知识(即查看内部源代码),它们都是真正的回声阴影。 该源代码涉及解析器以及操作码处理程序。 考虑一个简单的操作,例如显示数字零。 无论您使用echo还是打印,都会调用相同的处理程序“ZEND_ECHO_SPEC_CONST_HANDLER”。 打印处理程序在为echo调用处理程序之前做了一件事情,它确保print的返回值为1,如下所示:
ZVAL_LONG(&EX_T(opline->result.var).tmp_var, 1);
(请参阅此处以供参考)
如果希望在条件表达式中使用print,则返回值是一种方便。 为什么是1而不是100? 那么在PHP中,1或100的真实性是相同的,即true,而布尔上下文中的0相当于假值。 在PHP中,所有非零值(正值和负值)都是真值,这源于PHP的Perl遗留。
但是,如果是这种情况,那么人们可能会想知道为什么回声需要多个参数,而打印只能处理一个。 对于这个答案,我们需要转向解析器,特别是文件zend_language_parser.y 。 您会注意到,echo具有内置的灵活性,因此它可以打印一个或多个表达式(请参见此处)。 而打印仅限于打印一个表达式(请参阅此处)。
句法
在C编程语言和受其影响的语言(如PHP)中,语句和表达式之间存在区别。 在语法上, echo expr, expr, ... expr
是一个语句,而print expr
是一个表达式,因为它的计算结果是一个值。 因此,与其他语句一样, echo expr
独立存在,不能包含在表达式中:
5 + echo 6; // syntax error
相比之下, print expr
可以单独形成一个声明:
print 5; // valid
或者,成为一个表达的一部分:
$x = (5 + print 5); // 5
var_dump( $x ); // 6
有人可能会想到print
就好像它是一个一元操作符一样,就像!
或~
但它不是一个操作员。 什么!, ~ and print
有一个共同点,那就是它们都是PHP构建的,每个只有一个参数。 您可以使用print
来创建以下奇怪但有效的代码:
<?php
print print print print 7; // 7111
乍一看,最后一个打印语句首先打印其'7'操作数的结果看起来很奇怪。 但是,如果您深入挖掘并查看实际的操作码,这是有道理的:
line # * op fetch ext return operands
---------------------------------------------------------------------------------
3 0 > PRINT ~0 7
1 PRINT ~1 ~0
2 PRINT ~2 ~1
3 PRINT ~3 ~2
4 FREE ~3
5 > RETURN 1
产生的第一个操作码与'print 7'相对应。 '〜0'是一个临时变量,其值为1.该变量成为下一个打印操作码的操作数,并返回一个临时变量并重复该过程。 最后一个临时变量并没有被使用,所以它被释放了。
为什么print
返回一个值, echo
不?
表达式评估值。 例如2 + 3
评估为5
,而abs(-10)
评估为10
。 因为print expr
本身就是一个表达式,所以它应该保存一个值,它的值为1
表示一个真值结果,并且通过返回一个非零值,该表达式对包含在另一个表达式中变得有用。 例如,在这段代码中,print的返回值在确定函数序列时非常有用:
<?php
function bar( $baz ) {
// other code
}
function foo() {
return print("In and out ...n");
}
if ( foo() ) {
bar();
}
下面的例子说明了在运行时调试时您可能会发现特定值的打印:
<?php
$haystack = 'abcde';
$needle = 'f';
strpos($haystack,$needle) !== FALSE OR print "$needle not in $haystack";
// output: f not in abcde
作为一个侧面说明,一般来说,陈述不是表达式; 他们不会返回一个值。 当然,例外情况是表达式语句使用print,甚至用作陈述的简单表达式,例如1;
,这是PHP从C继承的语法。表达式语句可能看起来很奇怪,但它非常有用,可以将参数传递给函数。
print
功能?
不,它是一种语言结构。 虽然所有的函数调用都是表达式,但print (expr)
是一个表达式,尽管它的视觉效果好像使用了函数调用语法。 实际上,这些括号是括号 - 表达式语法,用于表达式评估。 这就解释了这样一个事实,即如果表达式是简单的,那么它们是可选的,例如print "Hello, world!"
。 用更复杂的表达方式如print (5 ** 2 + 6/2); // 28
print (5 ** 2 + 6/2); // 28
括号有助于表达式的评估。 与函数名不同, print
在语法上是关键字,在语义上是“语言结构”。
PHP中的术语“语言结构”通常指像isset
或empty
这样的“伪”函数。 虽然这些“构造”看起来完全像函数,但它们实际上是fexprs,也就是说,参数传递给它们而不被评估,这需要编译器的特殊处理。 print
恰好是一个fexpr,它选择以与函数相同的方式评估它的参数。
通过打印get_defined_functions()
可以看出差异:没有列出print
功能。 (虽然printf
和朋友是:不像print
,它们是真正的功能。)
为什么print(foo)然后工作?
出于与echo(foo)
一样的原因。 这些括号与函数调用括号完全不同,因为它们与表达式相关。 这就是为什么人们可以编码echo ( 5 + 8 )
并可以预期显示13的结果(请参阅参考资料)。 这些括号涉及评估表达式而不是调用函数。 注意:在PHP中还有其他用于括号的用法,例如if if条件表达式,赋值列表,函数声明等。
为什么print(1,2,3)
和echo(1,2,3)
导致语法错误?
语法是print expr
, echo expr
或echo expr, expr, ..., expr
。 当PHP遇到(1,2,3)
,它会尝试将其解析为单个表达式并失败,因为与C不同,PHP实际上没有二进制逗号运算符; 逗号更多地用作分隔符。 (尽管如此,您仍然可以在PHP的for循环中找到二进制逗号,它从C继承的语法。)
语义
声明echo e1, e2, ..., eN;
可以理解为echo e1; echo e2; ...; echo eN;
句法糖echo e1; echo e2; ...; echo eN;
echo e1; echo e2; ...; echo eN;
。
由于所有表达式都是语句,并且echo e
始终与print e
具有相同的副作用,并且在作为语句使用时, print e
的返回值被忽略,所以我们可以将echo e
理解为print e
语法糖。
这两个意见意味着echo e1, e2, ..., eN;
可以看作是print e1; print e2; ... print eN;
语法糖print e1; print e2; ... print eN;
print e1; print e2; ... print eN;
。 (但是,请注意下面的非语义运行时差异。)
因此我们只需要定义print
的语义。 print e
,评估时:
e
并键入 - 将结果值转换为字符串s
。 (因此, print e
相当于print (string) e
。) s
到输出缓冲器(其最终将被流传输到标准输出)。 1
。 字节码级别的差异
print
涉及填充返回变量(伪代码)的小开销
print 125;
PRINT 125,$temp ; print 125 and place 1 in $temp
UNSET $temp ; remove $temp
单个echo
编译为一个操作码:
echo 125;
ECHO 125
多值echo
编译为多个操作码
echo 123, 456;
ECHO 123
ECHO 456
请注意,多值echo
不会连接其参数,而是逐个输出它们。
参考: zend_do_print
, zend_do_echo
。
运行时差异
ZEND_PRINT
的实现过程如下(伪代码)
PRINT var, result:
result = 1
ECHO var
所以它基本上将1
放在结果变量中,并将真正的作业委托给ZEND_ECHO
处理程序。 ZEND_ECHO
执行以下操作
ECHO var:
if var is object
temp = var->toString()
zend_print_variable(temp)
else
zend_print_variable(var)
zend_print_variable()
执行实际的“打印”(实际上,它只是重定向到一个专用的SAPI函数)。
速度: echo x
vs print x
与echo不同, print分配一个临时变量。 然而,花在这个活动上的时间是微不足道的,所以这两种语言结构之间的差异可以忽略不计。
速度: echo a,b,c
vs echo abc
第一个编译成三个单独的语句。 第二个评估整个表达式abc
,打印结果并立即处理。 由于串联涉及内存分配和复制,因此第一个选项将更加高效。
那么使用哪一个?
在Web应用程序中,输出主要集中在模板中。 由于模板使用<?=
,这是echo
的别名,所以在代码的其他部分中坚持echo
也是合乎逻辑的。 echo
具有能够打印多个表达式而不连接它们的附加优点,并且不涉及填充临时返回变量的开销。 所以,使用echo
。
上一篇: Reference: Comparing PHP's print and echo
下一篇: Understanding the behavior of a single ampersand operator (&) on integers