Referência: Comparando impressão e eco do PHP


182

Qual é a diferença entre PHP printe echo?

O Stack Overflow tem muitas perguntas sobre o uso de PHP printe echopalavras - chave.

O objetivo deste post é fornecer uma pergunta de referência canônica e responder sobre PHP printe echopalavras-chave e comparar suas diferenças e casos de uso.


3
Acho que aqui não é suficiente sobre o valor de retorno de impressão. Imprimir é útil para saída rápida de depuração ou algo parecido: strpos ($ x, $ y)! == FALSE OU imprime "alguma coisa". Rápido para digitar e bom para ler. E "É imprimir uma função" foi difícil de ler por algum motivo (seu argumento parece ... estranho e não óbvio) - é uma construção de linguagem, há uma coisa muito pior que você não pode fazer com ela: funções variáveis.
XzKto

1
Para manter isso aberto, o que precisa ser feito aqui é: 1. divida em uma pergunta e resposta. 2. Referência / link para o conteúdo existente sobre o assunto no Stack Overflow (como aqui: stackoverflow.com/questions/3737139/… ), mas na resposta. 3. Precisa ser CW.
Kev

A "Coluna Relacionada" está correta, mas não é muito focada. Para aumentar seu valor como uma pergunta e resposta de referência canônica, também deve ser bem pesquisado e links para outras boas respostas específicas agregariam valor.
Kev

A pergunta realmente precisa ser uma pergunta real . Posso adicionar um banner referente à parte canônica quando terminar.
Tim Post

Respostas:


185

Por que duas construções?

A verdade sobre impressão e eco é que, embora eles apareçam para os usuários como duas construções distintas, ambos são realmente tons de eco se você começar o básico, ou seja, observe o código-fonte interno. Esse código fonte envolve o analisador e os manipuladores de código de operação. Considere uma ação simples, como exibir o número zero. Se você usa eco ou impressão, o mesmo manipulador "ZEND_ECHO_SPEC_CONST_HANDLER" será chamado. O manipulador para impressão faz uma coisa antes de chamar o manipulador para eco, garante que o valor de retorno para impressão seja 1, da seguinte maneira:

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

(veja aqui para referência )

O valor de retorno é uma conveniência, se desejar usar print em uma expressão condicional. Por que 1 e não 100? Bem, no PHP, a veracidade de 1 ou 100 é a mesma, ou seja, verdadeira, enquanto 0 em um contexto booleano equivale a um valor falso. No PHP, todos os valores diferentes de zero (positivo e negativo) são verdadeiros e isso deriva do legado Perl do PHP.

Mas, se esse for o caso, pode-se perguntar por que o eco aceita vários argumentos, enquanto a impressão pode apenas lidar com um. Para esta resposta, precisamos recorrer ao analisador, especificamente ao arquivo zend_language_parser.y . Você observará que o eco tem a flexibilidade incorporada para que possa imprimir uma ou várias expressões (veja aqui ). enquanto a impressão é restrita a imprimir apenas uma expressão (veja ).

Sintaxe

Na linguagem de programação C e nas linguagens influenciadas por ele, como PHP, há uma distinção entre instruções e expressões. Sintaticamente, echo expr, expr, ... expré uma declaração enquanto print expré uma expressão, pois é avaliada como um valor. Portanto, como outras declarações, echo expré independente e é incapaz de incluir em uma expressão:

5 + echo 6;   // syntax error

Por outro lado, print exprsozinho pode formar uma declaração:

print 5; // valid

Ou faça parte de uma expressão:

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

Pode-se ficar tentado a pensar printcomo se fosse um operador unário, como !ou ~no entanto não é um operador. O que !, ~ and printtem em comum é que todos eles estão embutidos no PHP e cada um leva apenas um argumento. Você pode usar printpara criar o seguinte código estranho, mas válido:

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

À primeira vista, o resultado pode parecer estranho que a última declaração de impressão imprime seu operando de '7' primeiro . Mas, se você se aprofundar e observar os opcodes reais, faz 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

O primeiro opcode gerado é o correspondente ao 'print 7'. O '~ 0' é uma variável temporária cujo valor é 1. Essa variável se torna e operando para o próximo código de operação de impressão que, por sua vez, retorna uma variável temporária e o processo se repete. A última variável temporária não é usada, portanto, é liberada.

Por que printretornar um valor e echonão?

Expressões avaliadas em valores. Por exemplo, 2 + 3é avaliada como 5, e abs(-10)avalia a 10. Como print exprela própria é uma expressão, ela deve conter um valor, e isso significa, um valor consistente 1indica um resultado verdadeiro e, ao retornar um valor diferente de zero, a expressão se torna útil para inclusão em outra expressão. Por exemplo, neste trecho, o valor de retorno de impressão é útil para determinar uma sequência de funções:

<?php

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

if ( foo() ) {

     bar();
}

Você pode encontrar uma impressão de valor específico quando se trata de depuração em tempo real, como o próximo exemplo ilustra:

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

// output: f not in abcde

Como uma nota lateral, geralmente, declarações não são expressões; eles não retornam um valor. A exceção, é claro, são declarações de expressão que usam expressões impressas e até simples usadas como declaração, como 1;uma sintaxe que o PHP herda de C. A declaração de expressão pode parecer estranha, mas é muito útil, possibilitando passar argumentos para funções.

É printuma função?

Não, é uma construção de linguagem. Embora todas as chamadas de função sejam expressões, print (expr)é uma expressão, apesar do visual que aparece como se estivesse usando a sintaxe da chamada de função. Na verdade, esses parênteses são parênteses-expr, úteis para avaliação de expressões. Isso explica o fato de que às vezes eles são opcionais se a expressão for simples, como print "Hello, world!". Com uma expressão mais complexa, como print (5 ** 2 + 6/2); // 28parênteses, ajuda na avaliação da expressão. Diferentemente dos nomes das funções, printé sintaticamente uma palavra-chave e semanticamente uma "construção de linguagem" .

O termo "construção de linguagem" no PHP geralmente se refere a funções "pseudo" como issetou empty. Embora essas "construções" pareçam exatamente com funções, elas são na verdade fexprs , ou seja, os argumentos são passados ​​para elas sem serem avaliadas, o que requer tratamento especial do compilador. printpassa a ser um fexpr que escolhe avaliar seu argumento da mesma maneira que uma função.

A diferença pode ser vista na impressão get_defined_functions(): não há nenhuma printfunção listada. (Embora printfe amigos sejam: ao contrário print, são verdadeiras funções.)

Por que a impressão (foo) funciona então?

Pela mesma razão que echo(foo)funciona. Esses parênteses são bem diferentes dos parênteses das chamadas de função porque, em vez disso, pertencem a expressões. É por isso que se pode codificar echo ( 5 + 8 )e esperar que um resultado 13 seja exibido (consulte a referência ). Esses parênteses estão envolvidos na avaliação de uma expressão, em vez de invocar uma função. Nota: existem outros usos para parênteses no PHP, como expressões if-condicionais, listas de atribuições, declarações de funções, etc.

Por que print(1,2,3)e echo(1,2,3)resultar em erros de sintaxe?

A sintaxe é print expr, echo exprou echo expr, expr, ..., expr. Quando o PHP encontra (1,2,3), ele tenta analisá-lo como uma única expressão e falha, porque, diferentemente de C, o PHP realmente não possui um operador de vírgula binária; a vírgula serve mais como separador. (Você pode encontrar uma vírgula binária, no entanto, nos for-loops do PHP, sintaxe herdada de C.)

Semântica

A afirmação echo e1, e2, ..., eN;pode ser entendida como açúcar sintático para echo e1; echo e2; ...; echo eN;.

Como todas as expressões são declarações, e echo esempre tem os mesmos efeitos colaterais que print e, e o valor de retorno de print eé ignorado quando usado como uma declaração, podemos entender echo ecomo açúcar sintático para print e.

Essas duas observações significam que echo e1, e2, ..., eN;pode ser visto como açúcar sintático para print e1; print e2; ... print eN;. (No entanto, observe as diferenças de tempo de execução não semânticas abaixo.)

Portanto, só precisamos definir a semântica para print. print e, quando avaliado:

  1. avalia seu argumento único ee converte o valor resultante em uma string s. (Assim, print eé equivalente a print (string) e.)
  2. Transmite a sequência spara o buffer de saída (que eventualmente será transmitido para a saída padrão).
  3. Avalia para o número inteiro 1.

Diferenças no nível do bytecode

print envolve uma pequena sobrecarga de preenchimento da variável de retorno (pseudocódigo)

print 125;

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

echocompilações únicas em um código de operação:

echo 125;

ECHO 125

echocompilações de vários valores em vários opcodes

echo 123, 456;

ECHO 123
ECHO 456

Observe que o valor múltiplo echonão concatena seus argumentos, mas os gera um por um.

Referência: zend_do_print, zend_do_echo.

Diferenças de tempo de execução

ZEND_PRINT é implementado da seguinte forma (pseudocódigo)

PRINT  var, result:

    result = 1
    ECHO var

Portanto, basicamente coloca 1a variável result e delega o trabalho real ao ZEND_ECHOmanipulador. ZEND_ECHOfaz o seguinte

ECHO var:

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

onde zend_print_variable()realiza a "impressão" real (na verdade, apenas redireciona para uma função SAPI dedicada).

Velocidade: echo xvsprint x

Ao contrário do eco , a impressão aloca uma variável temporária. No entanto, a quantidade de tempo gasto nessa atividade é minúscula; portanto, a diferença entre essas duas construções de linguagem é insignificante.

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

O primeiro compila até três instruções separadas. O segundo avalia a expressão inteira a.b.c., imprime o resultado e o descarta imediatamente. Como a concatenação envolve alocações de memória e cópia, a primeira opção será mais eficiente.

Então, qual usar?

Em aplicativos da Web, a saída é concentrada principalmente em modelos. Como os modelos usam <?=, que é o apelido de echo, também parece lógico manter echooutras partes do código. echopossui uma vantagem adicional de poder imprimir várias expressões sem concatená-las e não envolve a sobrecarga de preencher uma variável de retorno temporária. Então, use echo.


5
Eu extensivamente editei e esclareci isso e adicionei uma seção sobre semântica. Estou bastante confiante, mas alguém pode checar.
jameshfisher

1
Isso significa, então, que é melhor usar echo $a,$b,$cpara concatenação de vars de string? Sinceramente, nunca vi isso em uso.
Geoff

1
Que tal uma seção TL; DR descrevendo diferenças funcionais? Como: printpermite apenas um argumento, echopode ter múltiplos; echonão pode fazer parte de uma expressão enquanto printpode e retorna ...; e pode haver algum resumo de desempenho. E todos aqueles "por que" e "sob o capô" se
separam

0

Sei que estou atrasado, mas uma coisa que gostaria de acrescentar é que no meu código

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

dá um erro "erro de sintaxe, 'eco' inesperado (T_ECHO)"

enquanto

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

funciona bem.

Os documentos sobre eco dizem que "eco (diferente de outras construções de linguagem) não se comporta como uma função" aqui, mas sobre os documentos impressos também diz "impressão não é realmente uma função real (é uma construção de linguagem)" aqui . Então, eu não sei por que. E também sobre documentos de eco e impressão, diz: "As principais diferenças de eco são que a impressão aceita apenas um único argumento e sempre retorna 1". aqui

Ficaria feliz se alguém pudesse lançar alguma luz sobre esse comportamento.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.