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

PHP的printecho什么区别?

Stack Overflow有许多关于PHP的printecho关键字用法的问题。

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


为什么两个结构?

关于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中的术语“语言结构”通常指像issetempty这样的“伪”函数。 虽然这些“构造”看起来完全像函数,但它们实际上是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 exprecho exprecho 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_printzend_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

    链接地址: http://www.djcxy.com/p/9887.html

    上一篇: Reference: Comparing PHP's print and echo

    下一篇: Understanding the behavior of a single ampersand operator (&) on integers