Riferimento: confronto tra la printing e l'eco di PHP

Qual è la differenza tra la print e l' echo di PHP?

Stack Overflow ha molte domande relative all'utilizzo di parole chiave di print ed echo di PHP.

Lo scopo di questo post è fornire una domanda di riferimento canonica e una risposta alle parole chiave di print ed echo di PHP e confrontare le loro differenze e i casi d'uso.

Perché due costrutti?

La verità su printing ed eco è che mentre appaiono agli utenti come due distinti costrutti, sono entrambi davvero delle sfumature di eco se si arriva ai concetti di base, ovvero guarda il codice sorgente interno. Questo codice sorgente coinvolge sia il parser che i gestori di codice. Considera una semplice azione come la visualizzazione del numero zero. Sia che utilizzi echo o print, verrà richiamato lo stesso gestore "ZEND_ECHO_SPEC_CONST_HANDLER". Il gestore per la printing fa una cosa prima che invochi il gestore per l'eco, si assicura che il valore restituito per la printing sia 1, come segue:

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

(vedi qui per riferimento )

Il valore restituito è una comodità se si desidera utilizzare la printing in un'espressione condizionale. Perché 1 e non 100? Bene in PHP la veridicità di 1 o 100 è la stessa, cioè vera, mentre 0 in un context boolean equivale a un valore falso. In PHP tutti i valori diversi da zero (positivi e negativi) sono valori di verità e questo deriva dal patrimonio Perl di PHP.

Ma, se questo è il caso, allora ci si potrebbe chiedere perché echo prende più argomenti mentre la printing può gestirne solo uno. Per questa risposta dobbiamo rivolgerci al parser, in particolare al file zend_language_parser.y . Noterai che l'eco ha la flessibilità incorporata in modo che possa printingre una o più espressioni (vedi qui ). mentre la printing è vincasting alla printing di una sola espressione (vedi lì ).

Sintassi

Nel linguaggio di programmazione C e nelle lingue influenzate da esso come PHP, c'è una distinzione tra istruzioni ed espressioni. Sintatticamente, echo expr, expr, ... expr è una dichiarazione mentre print expr è un'espressione poiché valuta un valore. Pertanto, come altre affermazioni, echo expr sta da solo ed è incapace di inclusione in un'espressione:

 5 + echo 6; // syntax error 

Al contrario, print expr , può da solo formare una dichiarazione:

 print 5; // valid 

Oppure, sii parte di un'espressione:

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

Si potrebbe essere tentati di pensare alla print come se fosse un operatore unario, come ! o ~ tuttavia non è un operatore. What !, ~ and print hanno in comune il fatto che sono tutti integrati in PHP e ognuno richiede un solo argomento. Puoi usare print per creare il seguente codice strano ma valido:

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

A prima vista il risultato può sembrare strano che l'ultima istruzione di printing stampi prima il suo operando di "7". Ma se si approfondiscono e si guardano gli opcode effettivi, ha senso:

 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 

Il primo opcode che viene generato è quello corrispondente alla 'printing 7'. Il '~ 0' è una variabile temporanea il cui valore è 1. Quella variabile diventa e l'operando per il successivo opcode di printing che a sua volta restituisce una variabile temporanea e il process si ripete. L'ultima variabile temporanea non viene affatto utilizzata, quindi viene liberata.

Perché la print restituisce un valore e l' echo no?

Le espressioni valutano a valori. Ad esempio 2 + 3 restituisce 5 e abs(-10) valuta 10 . Poiché print expr è a sua volta un'espressione, quindi dovrebbe contenere un valore e lo fa, un valore coerente di 1 indica un risultato di verità e restituendo un valore diverso da zero l'espressione diventa utile per l'inclusione in un'altra espressione. Ad esempio in questo frammento, il valore di return della printing è utile per determinare una sequenza di funzioni:

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

È ansible trovare una printing di particolare valore quando si tratta di eseguire il debug al volo, come illustrato nell'esempio seguente:

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

Come nota a margine, in generale, le affermazioni non sono espressioni; non restituiscono un valore. L'exception, naturalmente, sono espressioni che usano espressioni di printing e anche semplici usate come un'istruzione, come 1; , una syntax che PHP eredita da C. L'espressione espressione può sembrare strana ma è molto utile, rendendo ansible passare argomenti a funzioni.

print una function?

No, è un costrutto linguistico. Mentre tutte le chiamate di function sono espressioni, print (expr) è un'espressione, nonostante la visualizzazione che appare come se stesse usando la syntax di chiamata di function. In verità queste parentesi sono syntax parentesi-expr, utile per la valutazione dell'espressione. Ciò spiega il fatto che a volte sono facoltativi se l'espressione è semplice, come ad esempio print "Hello, world!" . Con un'espressione più complessa come la print (5 ** 2 + 6/2); // 28 print (5 ** 2 + 6/2); // 28 le parentesi aiutano la valutazione dell'espressione. A differenza dei nomi delle funzioni, la print è sintatticamente una parola chiave e semanticamente un "costrutto linguistico" .

Il termine "costruzione del linguaggio" in PHP di solito si riferisce a funzioni "pseudo" come isset o empty . Sebbene questi "costrutti" assomiglino esattamente alle funzioni, in realtà sono fexprs , ovvero gli argomenti vengono passati a loro senza essere valutati, il che richiede un trattamento speciale dal compilatore. print capita di essere un fexpr che sceglie di valutare il suo argomento allo stesso modo di una function.

La differenza può essere vista printingndo get_defined_functions() : non è elencata alcuna function di print . (Anche se printf e gli amici sono: a differenza della print , sono vere funzioni.)

Perché funziona allora print (foo)?

Per la stessa ragione per cui echo(foo) funziona. Queste parentesi sono molto diverse dalle parentesi di una chiamata di function perché invece si riferiscono alle espressioni. Questo è il motivo per cui si può codice echo ( 5 + 8 ) e si può aspettare un risultato di 13 per visualizzare (vedi riferimento ). Queste parentesi sono coinvolte nella valutazione di un'espressione piuttosto che nel richiamo di una function. Nota: ci sono altri usi per le parentesi in PHP, come espressioni if ​​condizionali, liste di assegnazione, dichiarazioni di funzioni, ecc.

Perché print(1,2,3) ed echo(1,2,3) provocano errori di syntax?

La syntax è print expr , echo expr o echo expr, expr, ..., expr . Quando PHP incontra (1,2,3) , tenta di analizzarlo come singola espressione e fallisce, perché diversamente da C, PHP non ha realmente un operatore virgola binario; la virgola serve più come separatore. (Potete trovare comunque una virgola binaria in for-loops di PHP, syntax ereditata da C.)

Semantica

La dichiarazione echo e1, e2, ..., eN; può essere inteso come zucchero sintattico per echo e1; echo e2; ...; echo eN; echo e1; echo e2; ...; echo eN; .

Poiché tutte le espressioni sono affermazioni, e l' echo e ha sempre gli stessi effetti collaterali di print e , e il valore di return di print e viene ignorato quando usato come una dichiarazione, possiamo capire echo e come zucchero sintattico per la print e .

Queste due osservazioni significano che echo e1, e2, ..., eN; può essere visto come zucchero sintattico per la print e1; print e2; ... print eN; print e1; print e2; ... print eN; . (Tuttavia, notare le differenze di runtime non semantiche di seguito.)

Pertanto, dobbiamo solo definire la semantica per la print . print e , quando valutato:

  1. valuta il suo singolo argomento e e digita il valore risultante in una string s . (Quindi, print e è equivalente a print (string) e .)
  2. Trasmette la string s al buffer di output (che alla fine verrà trasmesso allo standard output).
  3. Valuta il numero integer 1 .

Differenze a livello di bytecode

print comport un piccolo overhead di popolamento della variabile di return (pseudocodice)

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

single echo compila in un opcode:

 echo 125; ECHO 125 

l' echo multivalore viene compilato su più codici opzionali

 echo 123, 456; ECHO 123 ECHO 456 

Nota che l' echo multi-valore non concatena i suoi argomenti, ma li restituisce uno per uno.

Riferimento: zend_do_print , zend_do_echo .

Differenze di runtime

ZEND_PRINT è implementato come segue (pseudocodice)

 PRINT var, result: result = 1 ECHO var 

Quindi in pratica mette 1 nella variabile risultato e delega il vero lavoro al gestore ZEND_ECHO . ZEND_ECHO fa quanto segue

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

where zend_print_variable() esegue la "printing" effettiva (in realtà, si limita a redirect a una function SAPI dedicata).

Velocità: echo x vs print x

A differenza di echo , print alloca una variabile temporanea. Tuttavia, la quantità di tempo speso per questa attività è minuscola, quindi la differenza tra questi due costrutti linguistici è trascurabile.

Velocità: echo a,b,c vs echo abc

Il primo compila fino a tre dichiarazioni separate. Il secondo valuta l'intera espressione abc , printing il risultato e lo smaltisce immediatamente. Dal momento che la concatenazione comport allocazioni di memory e copia, la prima opzione sarà più efficiente.

Quindi quale usare?

Nelle applicazioni web, l'output è per lo più concentrato in templates. Poiché i template usano <?= , Che è l'alias di echo , sembra logico attenersi echo in altre parti del codice. echo ha un ulteriore vantaggio di poter printingre più espressioni senza concatenarle e non comport un sovraccarico di popolamento di una variabile di return temporanea. Quindi, usa echo .