Referenz: Vergleichen von PHPs Druck und Echo

182

Was ist der Unterschied zwischen PHPs printund echo?

Stack Overflow hat viele Fragen zur Verwendung von PHP printund echoKeywords.

Der Zweck dieses Beitrags besteht darin, eine kanonische Referenzfrage und -antwort zu PHPs printund echoSchlüsselwörtern bereitzustellen und deren Unterschiede und Anwendungsfälle zu vergleichen.

Benutzer187291
quelle
3
Ich denke, hier reicht es nicht aus, den Druck zurückzugeben. Drucken ist nützlich für eine schnelle Debug-Ausgabe oder ähnliches: strpos ($ x, $ y)! == FALSE ODER drucke "etwas". Schnell zu tippen und gut zu lesen. Und "Is print a function" war aus irgendeinem Grund umständlich zu lesen (Ihre Argumentation scheint ... seltsam und nicht offensichtlich) - es ist ein Sprachkonstrukt, es gibt weitaus Schlimmeres, was Sie damit nicht tun können: variable Funktionen.
XzKto
1
Um dies offen zu halten, müssen Sie hier Folgendes tun: 1. Aufteilen in eine Frage und eine Antwort. 2. Verweis / Link auf vorhandenen Inhalt zum Thema " Stapelüberlauf" (ähnlich wie hier: stackoverflow.com/questions/3737139/… ), jedoch in der Antwort. 3. Muss CW sein.
Kev
Die "Verwandte Spalte" ist in Ordnung, aber nicht sehr fokussiert. Um seinen Wert als kanonische Referenzfrage und -antwort zu erhöhen, sollte er auch gut recherchiert sein und Links zu anderen spezifischen guten Antworten würden einen Mehrwert schaffen.
Kev
Die Frage muss wirklich eine tatsächliche Frage sein . Sobald Sie fertig sind, kann ich ein Banner zum kanonischen Teil hinzufügen.
Tim Post

Antworten:

185

Warum zwei Konstrukte?

Die Wahrheit über Druck und Echo ist, dass sie den Benutzern zwar als zwei unterschiedliche Konstrukte erscheinen, aber beide wirklich Echo-Schattierungen sind, wenn Sie sich auf die Grundlagen konzentrieren, dh den internen Quellcode betrachten. Dieser Quellcode umfasst sowohl den Parser als auch die Opcode-Handler. Stellen Sie sich eine einfache Aktion vor, z. B. die Anzeige der Zahl Null. Unabhängig davon, ob Sie Echo oder Print verwenden, wird derselbe Handler "ZEND_ECHO_SPEC_CONST_HANDLER" aufgerufen. Der Handler für den Druck führt eine Aktion aus, bevor er den Handler für das Echo aufruft. Er stellt sicher, dass der Rückgabewert für den Druck wie folgt 1 ist:

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

(siehe hier als Referenz )

Der Rückgabewert ist eine Annehmlichkeit, wenn Sie print in einem bedingten Ausdruck verwenden möchten. Warum 1 und nicht 100? Nun, in PHP ist die Wahrhaftigkeit von 1 oder 100 dieselbe, dh wahr, während 0 in einem booleschen Kontext einem falschen Wert entspricht. In PHP sind alle Nicht-Null-Werte (positiv und negativ) wahrheitsgemäße Werte, und dies ergibt sich aus dem Perl-Erbe von PHP.

Wenn dies jedoch der Fall ist, kann man sich fragen, warum Echo mehrere Argumente akzeptiert, während print nur eines verarbeiten kann. Für diese Antwort müssen wir uns an den Parser wenden, insbesondere an die Datei zend_language_parser.y . Sie werden feststellen, dass in Echo die Flexibilität eingebaut ist, dass ein oder mehrere Ausdrücke gedruckt werden können (siehe hier ). Während print nur einen Ausdruck drucken darf (siehe dort ).

Syntax

In der Programmiersprache C und von ihr beeinflussten Sprachen wie PHP wird zwischen Anweisungen und Ausdrücken unterschieden. Syntaktisch echo expr, expr, ... exprist eine Anweisung while print exprein Ausdruck, da sie einen Wert ergibt. Daher steht es wie andere Aussagen echo exprfür sich und kann nicht in einen Ausdruck aufgenommen werden:

5 + echo 6;   // syntax error

Im Gegensatz dazu print exprkann allein eine Aussage bilden:

print 5; // valid

Oder sei Teil eines Ausdrucks:

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

Man könnte versucht sein, sich vorzustellen, printals wäre es ein unärer Operator, wie !oder ~aber es ist kein Operator. Was !, ~ and printgemeinsam haben , ist , dass sie alle in PHP gebaut sind und jeweils nur ein Argument. Sie können printden folgenden seltsamen, aber gültigen Code erstellen:

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

Auf den ersten Blick kann das Ergebnis seltsam erscheinen , dass der letzte print - Anweisung druckt seine Operanden von ‚7‘ zuerst . Wenn Sie jedoch tiefer graben und sich die tatsächlichen Opcodes ansehen, ist dies sinnvoll:

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

Der allererste Opcode, der generiert wird, entspricht dem 'print 7'. Die '~ 0' ist eine temporäre Variable mit dem Wert 1. Diese Variable wird zum Operanden für den nächsten Druck-Opcode, der wiederum eine temporäre Variable zurückgibt und den Vorgang wiederholt. Die letzte temporäre Variable wird überhaupt nicht verwendet, sondern freigegeben.

Warum wird printein Wert zurückgegeben und echonicht?

Ausdrücke werden zu Werten ausgewertet. Zum Beispiel 2 + 3bewertet zu 5und abs(-10)bewertet zu 10. Da print expres sich selbst um einen Ausdruck handelt, sollte er einen Wert enthalten, und ein konsistenter Wert von 1zeigt ein wahrheitsgemäßes Ergebnis an. Durch die Rückgabe eines Werts ungleich Null wird der Ausdruck für die Aufnahme in einen anderen Ausdruck nützlich. In diesem Snippet ist beispielsweise der Rückgabewert von print hilfreich, um eine Funktionssequenz zu bestimmen:

<?php

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

if ( foo() ) {

     bar();
}

Möglicherweise finden Sie beim schnellen Debuggen einen Ausdruck von besonderem Wert, wie das nächste Beispiel zeigt:

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

// output: f not in abcde

Als Randnotiz sind Aussagen im Allgemeinen keine Ausdrücke; Sie geben keinen Wert zurück. Die Ausnahme bilden natürlich Ausdrucksanweisungen, die print verwenden, und sogar einfache Ausdrücke, die als Anweisung verwendet werden, z. B. 1;eine Syntax, die PHP von C erbt. Die Ausdrucksanweisung mag seltsam aussehen, ist jedoch sehr hilfreich und ermöglicht die Übergabe von Argumenten an Funktionen.

Ist printeine Funktion?

Nein, es ist ein Sprachkonstrukt. Während alle Funktionsaufrufe Ausdrücke sind, print (expr)handelt es sich trotz der visuellen Darstellung um einen Ausdruck, der so aussieht, als würde die Funktionsaufrufsyntax verwendet. In Wahrheit sind diese Klammern eine Klammern-Ausdruckssyntax, die für die Auswertung von Ausdrücken nützlich ist. Dies erklärt die Tatsache, dass sie manchmal optional sind, wenn der Ausdruck einfach ist, wie z print "Hello, world!". Bei einem komplexeren Ausdruck wie print (5 ** 2 + 6/2); // 28den Klammern hilft die Bewertung des Ausdrucks. Im Gegensatz zu Funktionsnamen printist es syntaktisch ein Schlüsselwort und semantisch ein "Sprachkonstrukt" .

Der Begriff "Sprachkonstrukt" in PHP bezieht sich normalerweise auf "Pseudo" -Funktionen wie issetoder empty. Obwohl diese "Konstrukte" genau wie Funktionen aussehen, handelt es sich tatsächlich um Fexprs , dh die Argumente werden an sie übergeben, ohne ausgewertet zu werden, was eine besondere Behandlung durch den Compiler erfordert. printzufällig ein fexpr, der sein Argument auf die gleiche Weise wie eine Funktion bewertet.

Der Unterschied ist beim Drucken erkennbar get_defined_functions(): Es ist keine printFunktion aufgeführt. (Obwohl printfund Freunde sind: im Gegensatz zu print, sind sie wahre Funktionen.)

Warum funktioniert print (foo) dann?

Aus dem gleichen Grund echo(foo)funktioniert das. Diese Klammern unterscheiden sich erheblich von Klammern für Funktionsaufrufe, da sie sich stattdessen auf Ausdrücke beziehen. Aus diesem Grund kann man codieren echo ( 5 + 8 )und erwarten, dass ein Ergebnis von 13 angezeigt wird (siehe Referenz ). Diese Klammern dienen dazu, einen Ausdruck auszuwerten, anstatt eine Funktion aufzurufen. Hinweis: Es gibt andere Verwendungszwecke für Klammern in PHP, z. B. wenn if-bedingte Ausdrücke, Zuweisungslisten, Funktionsdeklarationen usw.

Warum print(1,2,3)und echo(1,2,3)führen zu Syntaxfehlern?

Die Syntax ist print expr, echo exproder echo expr, expr, ..., expr. Wenn PHP auf etwas trifft (1,2,3), versucht es, es als einzelnen Ausdruck zu analysieren, und schlägt fehl, da PHP im Gegensatz zu C nicht wirklich über einen binären Kommaoperator verfügt. Das Komma dient eher als Trennzeichen. (Möglicherweise finden Sie dennoch ein binäres Komma in den for-Schleifen von PHP, dessen Syntax von C geerbt wurde.)

Semantik

Die Aussage echo e1, e2, ..., eN;kann als syntaktischer Zucker für verstanden werden echo e1; echo e2; ...; echo eN;.

Da alle Ausdrücke Anweisungen sind und echo eimmer die gleichen Nebenwirkungen haben wie print eund der Rückgabewert von print eignoriert wird, wenn er als Anweisung verwendet wird, können wir echo eals syntaktischen Zucker für verstehen print e.

Diese beiden Beobachtungen bedeuten, dass echo e1, e2, ..., eN;als syntaktischer Zucker für angesehen werden kann print e1; print e2; ... print eN;. (Beachten Sie jedoch die folgenden nicht-semantischen Laufzeitunterschiede.)

Wir müssen daher nur die Semantik für definieren print. print e, wenn bewertet:

  1. wertet sein einzelnes Argument aus eund wandelt den resultierenden Wert in eine Zeichenfolge um s. (Also print eist äquivalent zu print (string) e.)
  2. Streamen Sie die Zeichenfolge sin den Ausgabepuffer (der schließlich in die Standardausgabe gestreamt wird).
  3. Wertet die ganze Zahl aus 1.

Unterschiede auf Bytecode-Ebene

print Das Auffüllen der Rückgabevariablen (Pseudocode) ist mit einem geringen Aufwand verbunden.

print 125;

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

Single echokompiliert zu einem Opcode:

echo 125;

ECHO 125

Multi-Value- echoKompilierungen zu mehreren Opcodes

echo 123, 456;

ECHO 123
ECHO 456

Beachten Sie, dass Multi-Value echoseine Argumente nicht verkettet, sondern einzeln ausgibt.

Referenz: zend_do_print, zend_do_echo.

Laufzeitunterschiede

ZEND_PRINT wird wie folgt implementiert (Pseudocode)

PRINT  var, result:

    result = 1
    ECHO var

Es fügt also 1im Grunde die Ergebnisvariable ein und delegiert den eigentlichen Job an den ZEND_ECHOHandler. ZEND_ECHOmacht folgendes

ECHO var:

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

Dabei wird zend_print_variable()der eigentliche "Druck" ausgeführt (tatsächlich wird lediglich zu einer dedizierten SAPI-Funktion umgeleitet).

Geschwindigkeit: echo xvs.print x

Im Gegensatz zu Echo weist print eine temporäre Variable zu. Die für diese Aktivität aufgewendete Zeit ist jedoch winzig, so dass der Unterschied zwischen diesen beiden Sprachkonstrukten vernachlässigbar ist.

Geschwindigkeit: echo a,b,cvs.echo a.b.c

Die erste besteht aus drei separaten Anweisungen. Der zweite wertet den gesamten Ausdruck aus a.b.c., druckt das Ergebnis und entsorgt es sofort. Da die Verkettung Speicherzuweisungen und das Kopieren umfasst, ist die erste Option effizienter.

Also welches?

In Webanwendungen konzentriert sich die Ausgabe hauptsächlich auf Vorlagen. Da Vorlagen verwendet werden <?=, deren Alias ​​dies ist echo, erscheint es logisch, sich auch echoin anderen Teilen des Codes zu halten. echohat den zusätzlichen Vorteil, dass mehrere Ausdrücke gedruckt werden können, ohne sie zu verketten, und es ist kein Aufwand erforderlich, eine temporäre Rückgabevariable zu füllen. Also, benutze echo.

Benutzer187291
quelle
5
Ich habe dies ausführlich bearbeitet und geklärt und einen Abschnitt zur Semantik hinzugefügt. Ich bin ziemlich zuversichtlich, aber jemand könnte es noch einmal überprüfen.
Jameshfisher
1
Bedeutet dies also, dass es besser ist, echo $a,$b,$cString-Vars zu verketten? Ich habe das ehrlich gesagt noch nie in Gebrauch gesehen.
Geoff
1
Wie wäre es mit einem TL; DR-Abschnitt, der funktionale Unterschiede beschreibt? Wie: printerlaubt nur ein Argument, echokann mehrere haben; echokann nicht Teil eines Ausdrucks sein, solange printkann und zurückkehrt ...; und kann einige Leistungsübersicht sein. Und all diese "Warum" - und "Unter der Haube"
-Teile
0

Ich weiß, dass ich zu spät komme, aber eine Sache, die ich hinzufügen möchte, ist die in meinem Code

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

gibt einen Fehler "Syntaxfehler, unerwartetes 'Echo' (T_ECHO)"

während

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

funktioniert gut.

Docs über Echo sagt : „Echo ( im Gegensatz zu einigen anderen Sprachkonstrukte) verhält sich nicht wie eine Funktion“ hier aber über den Druck docs sagt auch „Druck nicht tatsächlich eine reelle Funktion ist (es ist ein Sprachkonstrukt)“ hier . Ich bin mir also nicht sicher warum. In Bezug auf Echo und Druckdokumente heißt es: "Die Hauptunterschiede zu Echo bestehen darin, dass der Druck nur ein einziges Argument akzeptiert und immer 1 zurückgibt." Hier

Ich würde mich freuen, wenn jemand etwas Licht in dieses Verhalten bringen kann.

Mahad Ali
quelle