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

2022-08-30 06:29:08

PHP 和 ?printecho

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

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


答案 1

为什么是两个结构?

关于打印回声的事实是,虽然它们在用户看来是两种不同的结构,但如果你深入到基础知识,即查看内部源代码,它们都是真正的回声阴影。该源代码涉及解析器以及操作码处理程序。考虑一个简单的操作,例如显示数字零。无论您使用 echo 还是 print,都将调用相同的处理程序“ZEND_ECHO_SPEC_CONST_HANDLER”。打印处理程序在调用回显处理程序之前执行一项操作,它确保 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, ... exprprint exprecho expr

5 + echo 6;   // syntax error

相反,,可以单独形成一个语句:print expr

print 5; // valid

或者,成为表达式的一部分:

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

人们可能会想把它想象成一个一元算子,就像或者它不是一个算子一样。它们的共同点是它们都内置于PHP中,每个都只需要一个参数。您可以使用 来创建以下奇怪但有效的代码:print!~!, ~ and printprint

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

生成的第一个操作码是对应于“print 7”的操作码。“~0”是一个临时变量,其值为 1。该变量成为下一个打印操作码的操作数,该操作码又返回一个临时变量,并且该过程重复。最后一个临时变量根本没有被使用,所以它被释放了。

为什么返回值而不返回?printecho

表达式的计算结果为值。例如,计算结果为 ,计算结果为 。由于它本身就是一个表达式,那么它应该保存一个值,并且它确实保存,一致的值表示一个真实的结果,并且通过返回一个非零值,表达式变得可用于包含在另一个表达式中。例如,在此代码段中,print 的返回值在确定函数序列时很有用:2 + 35abs(-10)10print expr1

<?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 的表达式语句,甚至是用作语句的简单表达式,例如 PHP 从 C 继承的语法。表达式语句可能看起来很奇怪,但它非常有用,可以向函数传递参数。1;

是函数吗?print

不,它是一种语言结构。虽然所有函数调用都是表达式,但都是表达式,尽管视觉对象看起来好像在使用函数调用语法。实际上,这些括号是括号-expr 语法,对于表达式计算很有用。这说明了这样一个事实,即如果表达式是简单的表达式,则有时它们是可选的,例如 .使用更复杂的表达式(如括号)有助于计算表达式。与函数名称不同,print 在语法上是一个关键字,在语义上是一个“语言构造”。print (expr)print "Hello, world!"print (5 ** 2 + 6/2); // 28

PHP中的术语“语言构造”通常是指“伪”函数,如或。虽然这些“构造”看起来与函数完全一样,但它们实际上是 fexprs,也就是说,参数在不被计算的情况下传递给它们,这需要编译器的特殊处理。 碰巧是一个 fexpr,它选择以与函数相同的方式计算其参数。issetemptyprint

通过打印可以看出差异:没有列出任何功能。(虽然和朋友是:不同,它们是真正的函数。get_defined_functions()printprintfprint

那么为什么print(foo)可以工作呢?

出于同样的原因,这有效。这些括号与函数调用括号完全不同,因为它们与表达式有关。这就是为什么人们可以编码并期望显示13的结果(参见参考)。这些括号涉及计算表达式而不是调用函数。注意:PHP中括号还有其他用途,例如if-conditional表达式,赋值列表,函数声明等。echo(foo)echo ( 5 + 8 )

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

语法为 或 。当PHP遇到时,它试图将其解析为单个表达式并失败,因为与C不同,PHP实际上没有二进制逗号运算符;逗号更多地用作分隔符。(您可能会在PHP的for循环中找到二进制逗号,语法继承自C。print exprecho exprecho expr, expr, ..., expr(1,2,3)

语义学

该语句可以理解为 的句法糖。echo e1, e2, ..., eN;echo e1; echo e2; ...; echo eN;

由于所有表达式都是语句,并且始终具有 与 相同的副作用,并且在用作语句时忽略 的返回值,因此我们可以理解为 语法糖 。echo eprint eprint eecho eprint e

这两个观察结果意味着,可以看作是句法糖。(但是,请注意下面的非语义运行时差异。echo e1, e2, ..., eN;print e1; print e2; ... print eN;

因此,我们只需要定义 的语义。,则在评估时:printprint e

  1. 计算其单个参数并将结果值类型转换为字符串 。(因此,等效于 。)esprint eprint (string) e
  2. 将字符串流式传输到输出缓冲区(最终将流式传输到标准输出)。s
  3. 计算结果为 整数 。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

因此,它基本上放入结果变量并将实际作业委托给处理程序。ZEND_ECHO执行以下操作1ZEND_ECHO

ECHO var:

    if var is object
        temp = var->toString()
        zend_print_variable(temp)
    else
        zend_print_variable(var)

其中执行实际的“打印”(实际上,它只是重定向到专用的SAPI函数)。zend_print_variable()

速度:与echo xprint x

echo 不同,print 会分配一个临时变量。但是,在此活动上花费的时间是微不足道的,因此这两种语言结构之间的差异可以忽略不计。

速度:与echo a,b,cecho a.b.c

第一个编译为三个单独的语句。第二个计算整个表达式,打印结果并立即处理。由于串联涉及内存分配和复制,因此第一个选项将更有效。a.b.c.

那么使用哪一个呢?

在 Web 应用程序中,输出主要集中在模板中。由于模板使用 ,这是 的别名,因此在代码的其他部分也坚持使用 似乎是合乎逻辑的。 还有一个额外的优点,即能够在不连接它们的情况下打印多个表达式,并且不涉及填充临时返回变量的开销。因此,请使用 .<?=echoechoechoecho


答案 2

print可以作为声明而存在而不需要 ;,这就是我们可以将其包含在$b; print "TRUE": print "FALSE";


推荐