Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reference: Comparing PHP's print and echo

Tags:

php

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:

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

(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 while print 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:

5 + echo 6;   // syntax error

In contrast, print expr, can alone form a statement:

print 5; // valid

Or, be part of an expression:

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

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 use print to create the following weird but valid code:

    <?php 
    print print print print 7; // 7111

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:

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

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 and echo doesn't?

Expressions evaluate to values. For example 2 + 3 evaluates to 5, and abs(-10) evaluates to 10. Since print expr is itself an expression, then it should hold a value and it does, a consistent value of 1 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:

<?php

function bar( $baz ) { 
   // other code   
}
function foo() {
  return print("In and out ...\n");
}

if ( foo() ) {

     bar();
}

You might find print of particular value when it comes to debugging on the fly, as the next example illustrates:

<?php
$haystack = 'abcde';
$needle = 'f';
strpos($haystack,$needle) !== FALSE OR print "$needle not in $haystack"; 

// output: f not in abcde

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 as1;, 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 as print "Hello, world!". With a more complex expression such as print (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 or empty. 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 no print function listed. (Though printf and friends are: unlike print, they are true functions.)

Why does print(foo) work then?

For the same reason thatecho(foo) works. These parentheses are quite different from function call parentheses because they pertain to expressions instead. That is why one may code echo ( 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) and echo(1,2,3) result in syntax errors?

The syntax is print expr, echo expr or echo 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 for echo e1; echo e2; ...; echo eN;.

Since all expressions are statements, and echo e always has the same side-effects as print e, and the return value of print e is ignored when used as a statement, we can understand echo e as syntactic sugar for print e.

These two observations mean that echo e1, e2, ..., eN; can be seen as syntactic sugar for print 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:

  1. evaluates its single argument e and type-casts the resulting value to a string s. (Thus, print e is equivalent to print (string) e.)
  2. Streams the string s to the output buffer (which eventually will be streamed to the standard output).
  3. Evaluates to the integer 1.

Differences at the bytecode level

print involves a small overhead of populating the return variable (pseudocode)

print 125;

PRINT  125,$temp     ; print 125 and place 1 in $temp 
UNSET  $temp         ; remove $temp

single echo compiles to one opcode:

echo 125;

ECHO 125

multi-value echo compiles to multiple opcodes

echo 123, 456;

ECHO 123
ECHO 456

Note 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)

PRINT  var, result:

    result = 1
    ECHO var

So it basically puts 1 in the result variable and delegates the real job to the ZEND_ECHO handler. ZEND_ECHO does the following

ECHO var:

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

where zend_print_variable() performs the actual "printing" (in fact, it merely redirects to a dedicated SAPI function).

Speed: echo x vs print 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 vs echo 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 of echo, it seems logical to stick to echo 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, use echo.