PHP 的 print和 echo有什么不同?
print
echo
StackOverflow 有许多关于 PHP 的 print和 echo关键字使用的问题。
这篇文章的目的是提供一个关于 PHP 的 print和 echo关键字的规范的 参考文献问题和答案,并比较它们之间的差异和用例。
关于 打印和 Echo的事实是,虽然它们在用户看来是两个不同的结构,但是如果你深入到基本的问题,比如说查看内部源代码,它们实际上都是 echo 的阴影。源代码包括解析器和操作码处理程序。考虑一个简单的操作,比如显示数字零。无论使用 echo 还是 print,都将调用相同的处理程序“ ZEND _ ECHO _ SPEC _ CONST _ HANDLER”。Print 的处理程序在调用 echo 的处理程序之前做一件事,它确保 print 的返回值为1,如下所示:
ZVAL_LONG(&EX_T(opline->result.var).tmp_var, 1);
(见 以供参考)
如果希望在条件表达式中使用 print,那么返回值是一个方便的选择。为什么是1而不是100?在 PHP 中,1或100的真值是相同的,即 true,而在布尔上下文中,0等同于一个假值。在 PHP 中,所有非零值(正值和负值)都是真值,这源于 PHP 的 Perl 遗产。
但是,如果是这种情况,那么人们可能想知道为什么 echo 采用多个参数,而 print 只能处理一个参数。对于这个答案,我们需要转向解析器,特别是文件 Zend _ language _ parser. y。您将注意到 echo 具有内置的灵活性,因此它可以打印一个或多个表达式(参见 给你)。而 print 只能打印一个表达式(参见 那里)。
在 C 编程语言和受其影响的语言(如 PHP)中,语句和表达式是有区别的。在语法上,echo expr, expr, ... expr是一个语句,而 print expr是一个表达式,因为它的计算结果是一个值。因此,与其他语句一样,echo expr是独立的,不能包含在一个表达式中:
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创建以下奇怪但有效的代码:
!
~
!, ~ and print
<?php print print print print 7; // 7111
乍一看,最后一个 print 语句打印的操作数是’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
生成的第一个操作码是对应于“ print7”的操作码。“ ~ 0”是一个临时变量,其值为1。该变量成为下一个打印操作码的操作数,而下一个打印操作码又返回一个临时变量,这个过程重复进行。最后一个临时变量根本没有被使用,所以它被释放了。
计算值的表达式。例如,2 + 3的计算结果为 5,而 abs(-10)的计算结果为 10。由于 print expr本身就是一个表达式,因此它应该保存一个值,而且它确实保存了,一致的 1值表示一个真实的结果,通过返回一个非零值,表达式对于包含在另一个表达式中变得有用。例如,在此代码片段中,print 的返回值在确定函数序列时非常有用:
2 + 3
5
abs(-10)
10
1
<?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 继承的语法。表达式语句可能看起来很奇怪,但它非常有用,使得向函数传递参数成为可能。
1;
不,这是一种语言结构。虽然所有的函数调用都是表达式,但是 print (expr)是一个表达式,尽管它看起来像是在使用函数调用语法。实际上,这些括号是括号 -expr 语法,对于表达式计算非常有用。这解释了这样一个事实: 如果表达式是一个简单的表达式,比如 print "Hello, world!",那么有时它们是可选的。对于更复杂的表达式(如 print (5 ** 2 + 6/2); // 28) ,括号有助于计算表达式。与函数名不同,print在语法上是一个关键字和语义上的 “语言结构”。
print (expr)
print "Hello, world!"
print (5 ** 2 + 6/2); // 28
PHP 中的术语“语言结构”通常指的是“伪”函数,如 isset或 empty。尽管这些“构造”看起来与函数完全一样,但它们实际上是 Fexprs,也就是说,参数传递给它们时没有进行计算,这需要编译器进行特殊处理。print恰好是一个 fexpr,它选择以与函数相同的方式计算参数。
isset
empty
通过打印 get_defined_functions()可以看出差异: 没有列出 print函数。(虽然 printf和朋友是: 不像 print,他们是真正的功能。)
get_defined_functions()
printf
和 echo(foo)的工作原理一样。这些括号与函数调用括号完全不同,因为它们属于表达式。这就是为什么我们可以编码 echo ( 5 + 8 ),并且可以期望显示13的结果(参见 参考文献)。这些括号用于计算表达式而不是调用函数。注意: 在 PHP 中括号还有其他用途,比如 if 条件表达式、赋值列表、函数声明等等。
echo(foo)
echo ( 5 + 8 )
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 expr, expr, ..., expr
(1,2,3)
语句 echo e1, e2, ..., eN;可以理解为 echo e1; echo e2; ...; echo eN;的句法糖。
echo e1, e2, ..., eN;
echo e1; echo e2; ...; echo eN;
由于所有的表达式都是语句,而且 echo e总是具有与 print e相同的副作用,并且在将 print e用作语句时忽略返回值,因此我们可以将 echo e理解为 print e的语法糖。
echo e
print e
这两个观察结果意味着 echo e1, e2, ..., eN;可以被看作是 print e1; print e2; ... print eN;的句法糖。(然而,请注意下面的非语义运行时差异。)
print e1; print e2; ... print eN;
因此,我们只需要为 print.print e定义语义,在计算时:
e
s
print (string) e
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_do_print
zend_do_echo
ZEND_PRINT 的实现如下(伪代码)
ZEND_PRINT
PRINT var, result: result = 1 ECHO var
因此,它基本上将 1放在 result 变量中,并将实际作业委托给 ZEND_ECHO处理程序。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 函数)。
zend_print_variable()
echo x
print x
与 Echo不同,打印分配一个临时变量。然而,花在这个活动上的时间很少,所以这两种语言结构之间的差异是可以忽略不计的。
echo a,b,c
echo a.b.c
第一个语句汇编成三个独立的语句。第二个程序计算整个表达式 a.b.c.,打印结果并立即处理它。因为连接涉及到内存分配和复制,所以第一个选项会更有效。
a.b.c.
在 Web 应用程序中,输出主要集中在模板中。因为模板使用 <?=,这是 echo的别名,所以在代码的其他部分也遵循 echo似乎是合乎逻辑的。echo还有一个额外的优势,它可以打印多个表达式而不需要连接它们,而且不需要填充临时返回变量。所以,使用 echo。
<?=
print可以作为语句存在,而不需要; ,这就是我们可以将它包含在 $b; print "TRUE": print "FALSE";中的原因
$b; print "TRUE": print "FALSE";