参考:比较PHP的打印和回声

PHP的printecho什么区别?

堆栈溢出有许多问题询问有关PHP的printecho关键字的用法。

这篇文章的目的是提供关于PHP的printecho关键字的标准参考问题和答案,并比较它们的差异和用例。

为什么两个构造?

关于printecho的事实是,虽然它们在用户看来是两个不同的构造,但是如果你深入到基础知识,也就是看内部源代码,它们都是真正的回声阴影。 该源代码涉及parsing器以及操作码处理程序。 考虑一个简单的操作,比如显示数字零。 无论您使用echo还是print,都会调用相同的处理函数“ZEND_ECHO_SPEC_CONST_HANDLER”。 打印处理程序在为echo调用处理程序之前做了一件事情,它确保print的返回值为1,如下所示:

 ZVAL_LONG(&EX_T(opline->result.var).tmp_var, 1); 

(请参阅这里以供参考 )

如果希望在条件expression式中使用print,返回值是一个方便。 为什么1而不是100? 那么在PHP中,1或100的真实性是相同的,即真,而布尔上下文中的0相当于假值。 在PHP中,所有非零值(正值和负值)都是真值,并且源于PHP的Perl遗留。

但是,如果是这样的话,那么人们可能会想知道为什么回声需要多个参数,而打印只能处理一个。 对于这个答案,我们需要转向parsing器,特别是文件zend_language_parser.y 。 您会注意到,echo具有内置的灵活性,因此可以打印一个或多个expression式(请参阅此处 )。 而打印仅限于打印一个expression式(请参阅此处 )。

句法

在C编程语言及其影响的语言如PHP中,语句和expression式之间是有区别的。 在语法上, echo expr, expr, ... expr是一个语句,而print expr是一个expression式,因为它的计算结果是一个值。 因此,和其他的声明一样, echo expr是独立的,不能包含在expression式中:

 5 + echo 6; // syntax error 

相比之下, print expr可以单独形成一个声明:

 print 5; // valid 

或者,成为一个expression的一部分:

  $x = (5 + print 5); // 5 var_dump( $x ); // 6 

有人可能会想到print就像是一个一元运算符,就像!~但是它不是一个操作员。 什么!, ~ and print有一个共同点,就是它们都是PHP构build的,每个只有一个参数。 您可以使用print来创build以下奇怪但有效的代码:

  <?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 

产生的第一个操作码是对应于“打印7”的操作码。 '〜0'是一个临时variables,它的值为1.该variables变成下一个打印操作码的操作数,而后者又返回一个临时variables并重复该过程。 最后一个临时variables并没有被使用,所以它被释放了。

为什么print返回一个值, echo不?

expression式评估值。 例如, 2 + 3评估为5abs(-10)评估为10 。 因为print expr本身就是一个expression式,所以它应该保存一个值,它的值是1表示一个真值结果,通过返回一个非零值,该expression式对于包含在另一个expression式中变得有用。 例如在这个片段中,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 

作为一个侧面说明,一般来说,陈述不是expression式; 他们不会返回一个值。 当然,例外情况是使用打印的expression式语句,甚至用作语句的简单expression式,例如1; ,PHP是从Cinheritance的语法。expression式语句可能看起来很奇怪,但它非常有用,可以将parameter passing给函数。

printfunction?

不,这是一种语言结构。 虽然所有的函数调用都是expression式,但是print (expr)是一个expression式,尽pipe这个expression式看起来就像使用函数调用语法一样。 实际上,这些括号是括号 – expression式语法,用于expression式评估。 这就解释了这样一个事实,即如果expression式是简单的,那么它们是可选的,例如print "Hello, world!" 。 用更复杂的expression方式如print (5 ** 2 + 6/2); // 28 print (5 ** 2 + 6/2); // 28括号帮助expression式的评估。 与函数名不同, print在语法上是关键字 ,在语义上是“语言结构” 。

PHP中的术语“语言结构”通常是指像“ isset或“ empty ”这样的“伪”函数。 尽pipe这些“构造”看起来和函数完全一样,但实际上它们是fexprs ,也就是说,parameter passing给它们而不被评估,这需要编译器给予特殊的处理。 print恰好是一个fexpr,select以同样的方式来评价它的论点。

通过打印get_defined_functions()可以看出差异:没有列出printfunction。 (虽然printf和朋友是:不像print ,他们是真正的function。)

为什么print(foo)工作呢?

出于同样的原因, echo(foo)作品。 这些括号与函数调用括号完全不同,因为它们与expression式相关。 这就是为什么人们可以编码echo ( 5 + 8 )并可以预期的结果13显示(见参考 )。 这些括号涉及到评估expression式而不是调用函数。 注意:在PHP中还有其他用于括号的用法,比如if-conditionalexpression式,赋值表,函数声明等。

为什么print(1,2,3)echo(1,2,3)导致语法错误?

语法是print exprecho exprecho expr, expr, ..., expr 。 当PHP遇到(1,2,3) ,它会尝试将其parsing为单个expression式并失败,因为与C不同,PHP实际上没有二进制逗号运算符; 逗号用作分隔符。 (尽pipe如此,您仍然可以在PHP的for循环中find二进制逗号,它从Cinheritance的语法。

语义

声明echo e1, e2, ..., eN; 可以理解为echo e1; echo e2; ...; echo eN;语法糖echo e1; echo e2; ...; echo eN; echo e1; echo e2; ...; echo eN;

由于所有的expression式都是语句,并且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 ,评估时:

  1. 评估它的单个参数e并input – 将结果值转换为strings 。 (因此, print e相当于print (string) e
  2. 将stringstream式传输到输出缓冲区 (最终将stream式传输到标准输出)。
  3. 评估到整数1

字节码级别的差异

print涉及填充返回variables(伪代码)

 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_printzend_do_echo

运行时差异

ZEND_PRINT实现如下(伪代码)

 PRINT var, result: result = 1 ECHO var 

所以它基本上将1放在结果variables中,并将真正的作业委托给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()执行实际的“打印”(实际上,它只是redirect到专用的SAPIfunction)。

速度: echo x vs print x

echo不同, print分配一个临时variables。 然而,花在这个活动上的时间是微不足道的,所以这两种语言结构之间的差异是微不足道的。

速度: echo a,b,c vs echo abc

第一个编译到三个单独的陈述。 第二个评估整个expression式abc ,打印结果立即configuration。 由于连接涉及内存分配和复制,所以第一个选项将会更高效。

那么使用哪一个?

在Web应用程序中,输出主要集中在模板中。 由于模板使用了<?= ,这是echo的别名,所以在代码的其他部分坚持echo也是合乎逻辑的。 echo有一个额外的好处是能够打印多个expression式,而不用连接它们,并且不涉及填充临时返回variables的开销。 所以,使用echo