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 lá ).
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:
- avalia seu argumento único
ee converte o valor resultante em uma string s. (Assim, print eé equivalente a print (string) e.)
- Transmite a sequência
spara o buffer de saída (que eventualmente será transmitido para a saída padrão).
- 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.