PHP的print和echo有什么区别?
PHP 的 print
和 echo
有什么区别?
Stack Overflow 有许多关于 PHP 的 print
和 echo
关键字用法的问题。
这篇文章的目的是提供一个规范的参考问题并回答 PHP 的 print
和 echo
关键字,并比较它们的差异和用例。
What is the difference between PHP's print
and echo
?
Stack Overflow has many questions asking about PHP's print
and echo
keyword usage.
The purpose of this post is to provide a canonical reference question and answer about PHP's print
and echo
keywords and compare their differences and use-cases.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
为什么有两个构造?
print 和 echo 的真相是,虽然它们对用户来说是两种不同的结构,但如果您深入了解基础知识,即查看内部源代码。该源代码涉及解析器以及操作码处理程序。考虑一个简单的操作,例如显示数字零。无论您使用 echo 还是 print,都会调用相同的处理程序“ ZEND_ECHO_SPEC_CONST_HANDLER”。 print 的处理程序在调用 echo 的处理程序之前做了一件事,它确保 print 的返回值为 1,如下所示:(
请参阅 此处供参考)
如果希望在条件表达式中使用 print,则返回值会很方便。为什么是 1 而不是 100?在 PHP 中,1 或 100 的真实性是相同的,即 true,而布尔上下文中的 0 等同于 false 值。在 PHP 中,所有非零值(正值和负值)都是真值,这源自 PHP 的 Perl 遗产。
但是,如果是这种情况,那么人们可能会想知道为什么 echo 需要多个参数,而 print 只能处理一个参数。为了得到这个答案,我们需要求助于解析器,特别是文件zend_language_parser.y。您会注意到 echo 具有内置的灵活性,因此它可以打印一个或多个表达式(请参阅 此处)。而 print 仅限于打印一个表达式(请参阅那里) 。
语法
在 C 编程语言和受其影响的语言(例如 PHP)中,语句和表达式之间存在区别。从语法上讲,
echo expr, expr, ... expr
是一个语句,而print expr
是一个表达式,因为它计算结果为一个值。因此,与其他语句一样,echo expr
独立存在,无法包含在表达式中:相反,
print expr
可以单独形成一个语句:或者,表达式的一部分:
人们可能会想将
print
视为一元运算符,例如!
或~
,但事实并非如此一个操作员。!、~ 和 print
的共同点是它们都内置于 PHP 中,并且每个都只接受一个参数。您可以使用print
创建以下奇怪但有效的代码:乍一看,结果可能看起来很奇怪,最后一个 print 语句首先打印其操作数“7”。但是,如果您深入挖掘并查看实际的操作码,就会发现它是有意义的:
生成的第一个操作码对应于“print 7”。 “~0”是一个临时变量,其值为 1。该变量成为下一个打印操作码的操作数,该操作码又返回一个临时变量并重复该过程。最后一个临时变量根本没有被使用,因此它被释放。
为什么
print
返回值而echo
不返回值?表达式求值。例如,
2 + 3
计算结果为5
,abs(-10)
计算结果为10
。由于print expr
本身就是一个表达式,因此它应该保存一个值,并且确实如此,一致的值1
表示结果为真,并且通过返回非零值来表示表达式对于包含在另一个表达式中变得有用。例如,在此代码片段中, print 的返回值对于确定函数序列很有用:当涉及到动态调试时,您可能会发现 print 具有特定值,如下例所示:
作为旁注,通常,语句不是表达式;他们不返回值。当然,例外的是使用 print 的表达式语句,甚至是用作语句的简单表达式,例如
1;
,这是 PHP 从 C 继承的语法。表达式语句可能看起来很奇怪,但它非常有用。很有帮助,可以将参数传递给函数。print
是一个函数吗?不,它是一种语言构造。虽然所有函数调用都是表达式,但
print (expr)
是一个表达式,尽管看起来好像在使用函数调用语法。事实上,这些括号是括号表达式语法,对于表达式求值很有用。这就解释了这样一个事实:如果表达式很简单,例如print "Hello, world!"
,有时它们是可选的。使用更复杂的表达式,例如print (5 ** 2 + 6/2); // 28
括号有助于表达式的求值。与函数名称不同,print
在语法上是一个关键字,并且在语义上是“语言构造”。PHP 中的术语“语言构造”通常指“伪”函数,例如
isset
或empty
。虽然这些“构造”看起来和函数一模一样,但它们实际上是 fexprs,也就是说,参数是传递给它们而不进行评估,这需要编译器的特殊处理。print
恰好是一个 fexpr,它选择以与函数相同的方式计算其参数。通过打印
get_define_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;
可以理解为的语法糖。代码>回显e1;回显e2; ...;回声eN;
。由于所有表达式都是语句,并且
echo e
总是与print e
具有相同的副作用,并且print e
的返回值被忽略当用作语句时,我们可以将echo e
理解为print e
的语法糖。这两个观察结果意味着
echo e1, e2, ..., eN;
可以被视为print e1; 的语法糖。打印e2; ...打印eN;
。 (但是,请注意下面的非语义运行时差异。)因此,我们只需定义
print
的语义。print e
,计算时:e
和 将结果值类型转换为字符串s
。 (因此,print e
相当于print (string) e
。)s
流式传输到 输出缓冲区(最终将流式传输到标准输出)。1
。字节码级别的差异
print
涉及填充返回变量(伪代码)的少量开销,单个
echo
编译为一个操作码:多值
echo
编译为多个操作码请注意,多值
echo
不会连接其参数,而是将它们一一输出。参考:
zend_do_print
,zend_do_echo
。运行时差异
ZEND_PRINT
的实现如下(伪代码),因此它基本上将
1
放入结果变量中,并将实际作业委托给ZEND_ECHO
处理程序。ZEND_ECHO
确实下面的代码中,
zend_print_variable()
执行实际的“打印”(事实上,它只是重定向到专用的 SAPI 函数)。速度:
echo x
与print x
与 echo 不同,print 分配一个临时变量。然而,花在这项活动上的时间很少,因此这两种语言结构之间的差异可以忽略不计。
速度:
echo a,b,c
与echo abc
第一个编译为三个单独的语句。第二个计算整个表达式
abc
,打印结果并立即处理它。由于串联涉及内存分配和复制,因此第一个选项会更有效。那么该使用哪一个呢?
在 Web 应用程序中,输出主要集中在模板中。由于模板使用
,它是
echo
的别名,因此在代码的其他部分也坚持使用echo
似乎是合乎逻辑的。 echo 的另一个优点是能够打印多个表达式而无需连接它们,并且不涉及填充临时返回变量的开销。因此,使用echo
。Why two constructs?
The truth about print and echo is that while they appear to users as two distinct constructs, they are both really shades of echo if you get down to basics, i.e. look at the internal source code. That source code involves the parser as well as opcode handlers. Consider a simple action such as displaying the number zero. Whether you use echo or print, the same handler " ZEND_ECHO_SPEC_CONST_HANDLER" will be invoked. The handler for print does one thing before it invokes the handler for echo, it makes sure that the return value for print is 1, as follows:
(see here for reference)
The return value is a convenience should one wish to use print in a conditional expression. Why 1 and not 100? Well in PHP the truthiness of 1 or 100 is the same, i.e. true, whereas 0 in a boolean context equates as a false value. In PHP all non-zero values (positive and negative) are truthy values and this derives from PHP's Perl legacy.
But, if this is the case, then one may wonder why echo take multiple arguments whereas print can only handle one. For this answer we need to turn to the parser, specifically the file zend_language_parser.y. You will note that echo has the flexibility built in so that it may print one or multiple expressions (see here). whereas print is constrained to printing only one expression (see there).
Syntax
In the C programming language and languages influenced by it such as PHP, there is a distinction between statements and expressions. Syntactically,
echo expr, expr, ... expr
is a statement whileprint expr
is an expression since it evaluates to a value. Therefore, like other statements,echo expr
stands on its own and is incapable of inclusion in an expression:In contrast,
print expr
, can alone form a statement:Or, be part of an expression:
One might be tempted to think of
print
as if it were a unary operator, like!
or~
however it is not an operator. What!, ~ and print
have in common is that they are all built into PHP and each takes only one argument. You can useprint
to create the following weird but valid code:At first glance the result may seem odd that the last print statement prints its operand of '7' first. But, if you dig deeper and look at the actual opcodes it makes sense:
The very first opcode that gets generated is that corresponding to the 'print 7'. The '~0' is a temporary variable whose value is 1. That variable becomes and operand for the next print opcode which in turn returns a temporary variable and the process repeats. The last temporary variable doesn't get used at all so, it gets freed.
Why does
print
return a value andecho
doesn't?Expressions evaluate to values. For example
2 + 3
evaluates to5
, andabs(-10)
evaluates to10
. Sinceprint expr
is itself an expression, then it should hold a value and it does, a consistent value of1
indicates a truthy result and by returning a non-zero value the expression becomes useful for inclusion in another expression. For example in this snippet, the return value of print is useful in determining a function sequence:You might find print of particular value when it comes to debugging on the fly, as the next example illustrates:
As a side-note, generally, statements are not expressions; they don't return a value. The exception, of course are expression statements which use print and even simple expressions used as a statement, such as
1;
, a syntax which PHP inherits from C. The expression statement may look odd but it is very helpful, making it possible to pass arguments to functions.Is
print
a function?No, it is a language construct. While all function calls are expressions,
print (expr)
is an expression, despite the visual which appears as if it were using function call syntax. In truth these parentheses are parentheses-expr syntax, useful for expression evaluation. That accounts for the fact that at times they are optional if the expression is a simple one, such asprint "Hello, world!"
. With a more complex expression such asprint (5 ** 2 + 6/2); // 28
the parentheses aid the evaluation of the expression. Unlike function names,print
is syntactically a keyword, and semantically a "language construct".The term "language construct" in PHP usually refers to "pseudo" functions like
isset
orempty
. Although these "constructs" look exactly like functions, they are actually fexprs, that is, the arguments are passed to them without being evaluated, which requires special treatment from the compiler.print
happens to be an fexpr that chooses to evaluate its argument in the same way as a function.The difference can be seen by printing
get_defined_functions()
: there is noprint
function listed. (Thoughprintf
and friends are: unlikeprint
, they are true functions.)Why does print(foo) work then?
For the same reason that
echo(foo)
works. These parentheses are quite different from function call parentheses because they pertain to expressions instead. That is why one may codeecho ( 5 + 8 )
and can expect a result of 13 to display (see reference). These parenthesis are involved in evaluating an expression rather than invoking a function. Note: there are other uses for parentheses in PHP, such as if if-conditional expressions, assignment lists, function declarations, etc.Why do
print(1,2,3)
andecho(1,2,3)
result in syntax errors?The syntax is
print expr
,echo expr
orecho expr, expr, ..., expr
. When PHP encounters(1,2,3)
, it tries to parse it as a single expression and fails, because unlike C, PHP does not really have a binary comma operator; the comma serves more as a separator. ( You may find a binary comma nonetheless in PHP's for-loops, syntax it inherited from C.)Semantics
The statement
echo e1, e2, ..., eN;
can be understood as syntactic sugar forecho e1; echo e2; ...; echo eN;
.Since all expressions are statements, and
echo e
always has the same side-effects asprint e
, and the return value ofprint e
is ignored when used as a statement, we can understandecho e
as syntactic sugar forprint e
.These two observations mean that
echo e1, e2, ..., eN;
can be seen as syntactic sugar forprint e1; print e2; ... print eN;
. (However, note the non-semantic runtime differences below.)We therefore only have to define the semantics for
print
.print e
, when evaluated:e
and type-casts the resulting value to a strings
. (Thus,print e
is equivalent toprint (string) e
.)s
to the output buffer (which eventually will be streamed to the standard output).1
.Differences at the bytecode level
print
involves a small overhead of populating the return variable (pseudocode)single
echo
compiles to one opcode:multi-value
echo
compiles to multiple opcodesNote that multi-value
echo
doesn't concatenate its arguments, but outputs them one-by-one.Reference:
zend_do_print
,zend_do_echo
.Runtime differences
ZEND_PRINT
is implemented as follows (pseudocode)So it basically puts
1
in the result variable and delegates the real job to theZEND_ECHO
handler.ZEND_ECHO
does the followingwhere
zend_print_variable()
performs the actual "printing" (in fact, it merely redirects to a dedicated SAPI function).Speed:
echo x
vsprint x
Unlike echo, print allocates a temporary variable. However, the amount of time spent on this activity is minuscule, so the difference between these two language constructs is negligible.
Speed:
echo a,b,c
vsecho a.b.c
The first one compiles down to three separate statements. The second evaluates the entire expression
a.b.c.
, prints the result and disposes it immediately. Since concatenation involves memory allocations and copying, the first option will be more efficient.So which one to use?
In web applications, output is mostly concentrated in templates. Since templates use
<?=
, which is the alias ofecho
, it seems logical to stick toecho
in other parts of code as well.echo
has an additional advantage of being able to print multiple expression without concatenating them and doesn't involve an overhead of populating a temporary return variable. So, useecho
.print
可以作为语句存在,而不需要 ;,这就是我们可以将其包含在$b; 中的原因。打印“真”:打印“假”;
print
may live as statement without the need of ;, and this is the reason that we may include it in a$b; print "TRUE": print "FALSE";