Referencia: Comparación de la impresión y el eco de PHP

182

¿Cuál es la diferencia entre PHP printy echo?

Stack Overflow tiene muchas preguntas sobre PHP printy el echouso de palabras clave.

El propósito de esta publicación es proporcionar una pregunta y respuesta de referencia canónica sobre PHP printy echopalabras clave y comparar sus diferencias y casos de uso.

usuario187291
fuente
3
Creo que aquí no basta con imprimir el valor de retorno. Imprimir es útil para una salida de depuración rápida o algo similar: strpos ($ x, $ y)! == FALSO O imprime "algo". Rápido para escribir y bueno para leer. Y "Es una función imprimir" fue difícil de leer por alguna razón (su argumentación parece ... extraña y no obvia): es una construcción del lenguaje, hay algo mucho peor que no puede hacer con ella: funciones variables.
XzKto
1
Para mantener esto abierto, lo que hay que hacer aquí es: 1. dividir en una pregunta y respuesta. 2. Referencia / enlace al contenido existente sobre el tema en Stack Overflow (algo así como: stackoverflow.com/questions/3737139/… ) pero en la respuesta. 3. Necesita ser CW.
Kev
La "columna relacionada" está bien, pero no está muy enfocada. Para aumentar su valor como una pregunta y respuesta de referencia canónica, también debe investigarse bien y los enlaces a otras buenas respuestas específicas agregarían valor.
Kev
La pregunta realmente necesita ser una pregunta real . Puedo agregarle un banner con respecto a la parte canónica una vez que haya terminado.
Tim Post

Respuestas:

185

¿Por qué dos construcciones?

La verdad acerca de la impresión y el eco es que, si bien los usuarios los ven como dos construcciones distintas, ambos son realmente sombras de eco si se llega a lo básico, es decir, mire el código fuente interno. Ese código fuente involucra tanto el analizador como los manejadores de código de operación. Considere una acción simple como mostrar el número cero. Ya sea que use echo o print, se invocará el mismo controlador "ZEND_ECHO_SPEC_CONST_HANDLER". El controlador para imprimir hace una cosa antes de invocar al controlador para echo, se asegura de que el valor de retorno para print sea 1, de la siguiente manera:

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

(ver aquí para referencia )

El valor de retorno es conveniente si se desea utilizar print en una expresión condicional. ¿Por qué 1 y no 100? Bueno, en PHP, la veracidad de 1 o 100 es la misma, es decir, verdadera, mientras que 0 en un contexto booleano equivale a un valor falso. En PHP, todos los valores distintos de cero (positivo y negativo) son valores verdaderos y esto se deriva del legado de Perl de PHP.

Pero, si este es el caso, entonces uno puede preguntarse por qué echo toma múltiples argumentos mientras que print solo puede manejar uno. Para esta respuesta, debemos recurrir al analizador, específicamente al archivo zend_language_parser.y . Notarás que echo tiene la flexibilidad incorporada para que pueda imprimir una o varias expresiones (ver aquí ). mientras que print se limita a imprimir solo una expresión (ver allí ).

Sintaxis

En el lenguaje de programación C y los lenguajes influenciados por él, como PHP, hay una distinción entre declaraciones y expresiones. Sintácticamente, echo expr, expr, ... expres una declaración, mientras que print expres una expresión, ya que se evalúa como un valor. Por lo tanto, como otras declaraciones, se echo exprsostiene por sí solo y es incapaz de ser incluido en una expresión:

5 + echo 6;   // syntax error

Por el contrario, print exprsolo puede formar una declaración:

print 5; // valid

O ser parte de una expresión:

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

Uno podría sentirse tentado a pensar printque se trata de un operador unario, como !o ~no es un operador. Lo que !, ~ and printtienen en común es que todos están integrados en PHP y cada uno toma solo un argumento. Puede usar printpara crear el siguiente código extraño pero válido:

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

A primera vista, el resultado puede parecer extraño que la última declaración de impresión imprima primero su operando de '7' . Pero, si profundiza y mira los códigos de operación reales, tiene sentido:

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

El primer código de operación que se genera es el correspondiente a la 'impresión 7'. El '~ 0' es una variable temporal cuyo valor es 1. Esa variable se convierte y operando para el siguiente código de operación de impresión que a su vez devuelve una variable temporal y el proceso se repite. La última variable temporal no se usa en absoluto, por lo que se libera.

¿Por qué printdevuelve un valor y echono lo hace?

Las expresiones evalúan los valores. Por ejemplo 2 + 3evalúa a 5, y abs(-10)se evalúa como 10. Dado que print expres en sí misma una expresión, entonces debe contener un valor y lo hace, un valor consistente de 1indica un resultado verdadero y al devolver un valor distinto de cero la expresión se vuelve útil para su inclusión en otra expresión. Por ejemplo, en este fragmento, el valor de retorno de print es útil para determinar una secuencia de funciones:

<?php

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

if ( foo() ) {

     bar();
}

Puede encontrar impresiones de un valor particular cuando se trata de depurar sobre la marcha, como lo ilustra el siguiente ejemplo:

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

// output: f not in abcde

Como nota al margen, en general, las declaraciones no son expresiones; No devuelven un valor. La excepción, por supuesto, son las declaraciones de expresión que usan expresiones impresas e incluso simples usadas como una declaración, como 1;una sintaxis que PHP hereda de C. La declaración de expresión puede parecer extraña pero es muy útil, ya que permite pasar argumentos a funciones

Es printuna función?

No, es una construcción de lenguaje. Si bien todas las llamadas a funciones son expresiones, print (expr)es una expresión, a pesar de lo visual que aparece como si estuviera usando la sintaxis de llamadas a funciones. En verdad, estos paréntesis son sintaxis paréntesis-expr, útiles para la evaluación de expresiones. Eso explica el hecho de que a veces son opcionales si la expresión es simple, como print "Hello, world!". Con una expresión más compleja, como print (5 ** 2 + 6/2); // 28los paréntesis, ayuda a evaluar la expresión. A diferencia de los nombres de funciones, printes sintácticamente una palabra clave y semánticamente una "construcción de lenguaje" .

El término "construcción de lenguaje" en PHP generalmente se refiere a funciones "pseudo" como isseto empty. Aunque estas "construcciones" se ven exactamente como funciones, en realidad son fexprs , es decir, los argumentos se les pasan sin ser evaluados, lo que requiere un tratamiento especial del compilador. printresulta ser un fexpr que elige evaluar su argumento de la misma manera que una función.

La diferencia se puede ver imprimiendo get_defined_functions(): no hay ninguna printfunción en la lista. (Aunque los printfamigos son: a diferencia print, son funciones verdaderas).

¿Por qué funciona print (foo) entonces?

Por la misma razón que echo(foo)funciona. Estos paréntesis son bastante diferentes de los paréntesis de llamadas a funciones porque pertenecen a expresiones en su lugar. Es por eso que uno puede codificar echo ( 5 + 8 )y esperar que se muestre un resultado de 13 (ver referencia ). Estos paréntesis están involucrados en la evaluación de una expresión en lugar de invocar una función. Nota: hay otros usos para paréntesis en PHP, como expresiones if-conditional, listas de asignación, declaraciones de funciones, etc.

¿Por qué hacer print(1,2,3)y echo(1,2,3)dar lugar a errores de sintaxis?

La sintaxis es print expr, echo exproecho expr, expr, ..., expr . Cuando PHP se encuentra (1,2,3), intenta analizarlo como una sola expresión y falla, porque a diferencia de C, PHP realmente no tiene un operador de coma binario; la coma sirve más como separador. (No obstante, puede encontrar una coma binaria en los bucles for de PHP, sintaxis que heredó de C.)

Semántica

La declaración echo e1, e2, ..., eN;puede entenderse como azúcar sintáctica paraecho e1; echo e2; ...; echo eN; .

Como todas las expresiones son declaraciones y echo esiempre tienen los mismos efectos secundarios que print e, y el valor de retorno de print ese ignora cuando se usa como una declaración, podemos entenderlo echo ecomo azúcar sintáctica paraprint e .

Estas dos observaciones significan que echo e1, e2, ..., eN;puede verse como azúcar sintáctica paraprint e1; print e2; ... print eN; . (Sin embargo, tenga en cuenta las diferencias de tiempo de ejecución no semánticas a continuación).

Por lo tanto, solo tenemos que definir la semántica para print. print e, cuando se evalúa:

  1. evalúa su argumento único ey convierte el valor resultante en una cadena s. (Por lo tanto, print ees equivalente a print (string) e).
  2. Transmite la cadena sal búfer de salida (que eventualmente se transmitirá a la salida estándar).
  3. Evalúa al entero 1.

Diferencias a nivel de bytecode

print implica una pequeña sobrecarga de poblar la variable de retorno (pseudocódigo)

print 125;

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

echocompilaciones individuales en un código de operación:

echo 125;

ECHO 125

echocompilaciones de múltiples valores para múltiples códigos de operación

echo 123, 456;

ECHO 123
ECHO 456

Tenga en cuenta que el valor múltiple echono concatena sus argumentos, sino que los genera uno por uno.

Referencia: zend_do_print, zend_do_echo.

Diferencias de tiempo de ejecución

ZEND_PRINT se implementa de la siguiente manera (pseudocódigo)

PRINT  var, result:

    result = 1
    ECHO var

Por lo tanto, básicamente coloca 1la variable de resultado y delega el trabajo real al ZEND_ECHOcontrolador. ZEND_ECHOhace lo siguiente

ECHO var:

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

donde zend_print_variable()realiza la "impresión" real (de hecho, simplemente redirige a una función SAPI dedicada).

Velocidad: echo xvsprint x

A diferencia de echo , print asigna una variable temporal. Sin embargo, la cantidad de tiempo dedicado a esta actividad es minúscula, por lo que la diferencia entre estas dos construcciones de lenguaje es insignificante.

Velocidad: echo a,b,cvsecho a.b.c

El primero se resume en tres declaraciones separadas. El segundo evalúa la expresión completa.a.b.c. , imprime el resultado y lo elimina de inmediato. Dado que la concatenación implica asignaciones de memoria y copia, la primera opción será más eficiente.

Entonces, ¿cuál usar?

En aplicaciones web, la salida se concentra principalmente en plantillas. Dado que las plantillas usan <?=, que es el alias de echo, parece lógico seguir echoen otras partes del código también. echotiene una ventaja adicional de poder imprimir múltiples expresiones sin concatenarlas y no implica una sobrecarga de llenar una variable de retorno temporal. Entonces, use echo.

usuario187291
fuente
55
He editado y aclarado ampliamente esto, y he agregado una sección sobre semántica. Estoy bastante seguro de ello, pero alguien podría verificarlo dos veces.
jameshfisher
1
¿Significa esto, entonces, que es mejor usarlo echo $a,$b,$cpara la concatenación de cadenas vars? Sinceramente, nunca he visto esto en uso.
geoff
1
¿Qué tal una sección TL; DR que describe las diferencias funcionales? Me gusta: printpermite solo un argumento, echopuede tener múltiples; echono puede ser parte de una expresión mientras printcan y devuelve ...; y puede haber algún resumen de rendimiento. Y todas esas partes de "por qué" y "bajo el capó" después
YakovL
0

Sé que llego tarde, pero una cosa que me gustaría agregar es que en mi código

 $stmt = mysqli_stmt_init($connection) or echo "error at init"; 

da un error "error de sintaxis, 'eco' inesperado (T_ECHO)"

mientras

 $stmt = mysqli_stmt_init($connection) or print "error at init";

funciona bien.

Los documentos sobre echo dicen "echo (a diferencia de otras construcciones de lenguaje) no se comporta como una función" aquí, pero acerca de print docs también dice "print no es realmente una función real (es una construcción de lenguaje)" aquí . Entonces no estoy seguro de por qué. Y también sobre echo e print docs dice "Las principales diferencias con echo son que print solo acepta un argumento y siempre devuelve 1". aquí

Sería feliz si alguien puede arrojar algo de luz sobre este comportamiento.

Mahad Ali
fuente