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 expr
sozinho 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 print
como se fosse um operador unário, como !
ou ~
no entanto não é um operador. O que !, ~ and print
tem em comum é que todos eles estão embutidos no PHP e cada um leva apenas um argumento. Você pode usar print
para 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 print
retornar um valor e echo
não?
Expressões avaliadas em valores. Por exemplo, 2 + 3
é avaliada como 5
, e abs(-10)
avalia a 10
. Como print expr
ela própria é uma expressão, ela deve conter um valor, e isso significa, um valor consistente 1
indica 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.
É print
uma 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); // 28
parê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 isset
ou 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. print
passa 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 print
função listada. (Embora printf
e 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 expr
ou 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 e
sempre 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 e
como 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
e
e converte o valor resultante em uma string s
. (Assim, print e
é equivalente a print (string) e
.)
- Transmite a sequência
s
para 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
echo
compilações únicas em um código de operação:
echo 125;
ECHO 125
echo
compilações de vários valores em vários opcodes
echo 123, 456;
ECHO 123
ECHO 456
Observe que o valor múltiplo echo
nã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 1
a variável result e delega o trabalho real ao ZEND_ECHO
manipulador. ZEND_ECHO
faz 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 x
vsprint 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,c
vsecho 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 echo
outras partes do código. echo
possui 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
.