Erst kürzlich habe ich wieder gehört, dass PHP-Leute immer noch über einfache Anführungszeichen vs. doppelte Anführungszeichen sprechen und dass die Verwendung von einfachen Anführungszeichen nur eine Mikrooptimierung ist, aber wenn man sich daran gewöhnt, ständig einfache Anführungszeichen zu verwenden, würde man eine Menge CPU sparen Zyklen!
„Alles ist schon gesagt, aber noch nicht von allen“ – Karl Valentin
In diesem Sinne schreibe ich einen Artikel über dasselbe Thema, das Nikita Popov bereits vor 12 Jahren geschrieben hat (wenn Sie seinen Artikel lesen, können Sie hier aufhören zu lesen).
PHP führt eine String-Interpolation durch, bei der es nach der Verwendung von Variablen in einem String sucht und diese durch den Wert der verwendeten Variablen ersetzt:
$juice = "apple"; echo "They drank some $juice juice."; // will output: They drank some apple juice.
Diese Funktion ist auf Zeichenfolgen in doppelten Anführungszeichen und Heredoc beschränkt. Die Verwendung von einfachen Anführungszeichen (oder nowdoc) führt zu einem anderen Ergebnis:
$juice = "apple"; echo 'They drank some $juice juice.'; // will output: They drank some $juice juice.
Sehen Sie sich das an: PHP sucht nicht nach Variablen in dieser Zeichenfolge in einfachen Anführungszeichen. Wir könnten also einfach überall einfache Anführungszeichen verwenden. Also fingen die Leute an, solche Änderungen vorzuschlagen..
- $juice = "apple"; + $juice = 'apple';
.. weil es schneller ist und bei jeder Ausführung dieses Codes eine Menge CPU-Zyklen einspart, weil PHP nicht nach Variablen in Zeichenfolgen in einfachen Anführungszeichen sucht (die im Beispiel sowieso nicht vorhanden sind) und Alle sind zufrieden, Fall abgeschlossen.
Natürlich gibt es einen Unterschied zwischen einfachen und doppelten Anführungszeichen, aber um zu verstehen, was vor sich geht, müssen wir etwas tiefer graben.
Obwohl PHP eine interpretierte Sprache ist, verwendet es einen Kompilierungsschritt, bei dem bestimmte Teile zusammenspielen, um etwas zu erhalten, das die virtuelle Maschine tatsächlich ausführen kann, nämlich Opcodes. Wie kommen wir also vom PHP-Quellcode zu Opcodes?
Der Lexer scannt die Quellcodedatei und zerlegt sie in Token. Ein einfaches Beispiel dafür, was das bedeutet, finden Sie in der Dokumentation der Funktion token_get_all(). Ein PHP-Quellcode von nur
T_OPEN_TAG (<?php ) T_ECHO (echo) T_WHITESPACE ( ) T_CONSTANT_ENCAPSED_STRING ("")
Wir können dies in diesem 3v4l.org-Snippet in Aktion sehen und damit spielen.
Der Parser nimmt diese Token und generiert daraus einen abstrakten Syntaxbaum. Eine AST-Darstellung des obigen Beispiels sieht in JSON-Darstellung wie folgt aus:
{ "data": [ { "nodeType": "Stmt_Echo", "attributes": { "startLine": 1, "startTokenPos": 1, "startFilePos": 6, "endLine": 1, "endTokenPos": 4, "endFilePos": 13 }, "exprs": [ { "nodeType": "Scalar_String", "attributes": { "startLine": 1, "startTokenPos": 3, "startFilePos": 11, "endLine": 1, "endTokenPos": 3, "endFilePos": 12, "kind": 2, "rawValue": "\"\"" }, "value": "" } ] } ] }
Falls Sie auch damit herumspielen und sehen möchten, wie der AST für anderen Code aussieht, habe ich https://phpast.com/ von Ryan Chandler und https://php-ast-viewer.com/ gefunden Beide zeigen Ihnen den AST eines bestimmten PHP-Codestücks.
Der Compiler nimmt den AST und erstellt Opcodes. Die Opcodes sind die Dinge, die die virtuelle Maschine ausführt. Sie werden auch im OPcache gespeichert, wenn Sie dies eingerichtet und aktiviert haben (was ich sehr empfehle).
Um die Opcodes anzuzeigen, haben wir mehrere Möglichkeiten (vielleicht mehr, aber ich kenne diese drei):
$ echo '<?php echo "";' > foo.php $ php -dopcache.opt_debug_level=0x10000 foo.php $_main: ... 0000 ECHO string("") 0001 RETURN int(1) </p> <h2> Hypothese </h2> <p>Um auf die ursprüngliche Idee der Einsparung von CPU-Zyklen bei der Verwendung von einfachen Anführungszeichen gegenüber doppelten Anführungszeichen zurückzukommen: Ich denke, wir sind uns alle einig, dass dies nur dann zutrifft, wenn PHP diese Zeichenfolgen zur Laufzeit für jede einzelne Anfrage auswerten würde.</p> <h2> Was passiert zur Laufzeit? </h2> <p>Mal sehen, welche Opcodes PHP für die beiden verschiedenen Versionen erstellt.</p> <p>Doppelte Anführungszeichen:<br> </p> <pre class="brush:php;toolbar:false"><?php echo "apple";
0000 ECHO string("apple") 0001 RETURN int(1)
vs. einfache Anführungszeichen:
<?php echo 'apple';
0000 ECHO string("apple") 0001 RETURN int(1)
Hey, warte, etwas Seltsames ist passiert. Das sieht identisch aus! Wo ist meine Mikrooptimierung geblieben?
Nun, vielleicht, nur vielleicht analysiert die Implementierung des ECHO-Opcode-Handlers die angegebene Zeichenfolge, obwohl es keine Markierung oder etwas anderes gibt, das sie dazu auffordert ... hmm ?
Lassen Sie uns einen anderen Ansatz ausprobieren und sehen, was der Lexer in diesen beiden Fällen tut:
Doppelte Anführungszeichen:
T_OPEN_TAG (<?php ) T_ECHO (echo) T_WHITESPACE ( ) T_CONSTANT_ENCAPSED_STRING ("")
vs. einfache Anführungszeichen:
Line 1: T_OPEN_TAG (<?php ) Line 1: T_ECHO (echo) Line 1: T_WHITESPACE ( ) Line 1: T_CONSTANT_ENCAPSED_STRING ('')
Die Token unterscheiden immer noch zwischen doppelten und einfachen Anführungszeichen, aber die Überprüfung des AST liefert uns in beiden Fällen ein identisches Ergebnis – der einzige Unterschied ist der rawValue in den Scalar_String-Knotenattributen, der immer noch die einfachen/doppelten Anführungszeichen enthält, aber Der Wert verwendet in beiden Fällen doppelte Anführungszeichen.
Könnte es sein, dass die String-Interpolation tatsächlich zur Kompilierzeit erfolgt?
Lassen Sie es uns anhand eines etwas „anspruchsvolleren“ Beispiels überprüfen:
<?php $juice="apple"; echo "juice: $juice";
Tokens für diese Datei sind:
T_OPEN_TAG (<?php) T_VARIABLE ($juice) T_CONSTANT_ENCAPSED_STRING ("apple") T_WHITESPACE () T_ECHO (echo) T_WHITESPACE ( ) T_ENCAPSED_AND_WHITESPACE (juice: ) T_VARIABLE ($juice)
Look at the last two tokens! String interpolation is handled in the lexer and as such is a compile time thing and has nothing to do with runtime.
For completeness, let's have a look at the opcodes generated by this (after optimisation, using 0x20000):
0000 ASSIGN CV0($juice) string("apple") 0001 T2 = FAST_CONCAT string("juice: ") CV0($juice) 0002 ECHO T2 0003 RETURN int(1)
This is different opcode than we had in our simple
Let's have a look at these three different versions:
<?php $juice = "apple"; echo "juice: $juice $juice"; echo "juice: ", $juice, " ", $juice; echo "juice: ".$juice." ".$juice;
The first opcode assigns the string "apple" to the variable $juice:
0000 ASSIGN CV0($juice) string("apple")
The first version (string interpolation) is using a rope as the underlying data structure, which is optimised to do as little string copies as possible.
0001 T2 = ROPE_INIT 4 string("juice: ") 0002 T2 = ROPE_ADD 1 T2 CV0($juice) 0003 T2 = ROPE_ADD 2 T2 string(" ") 0004 T1 = ROPE_END 3 T2 CV0($juice) 0005 ECHO T1
The second version is the most memory effective as it does not create an intermediate string representation. Instead it does multiple calls to ECHO which is a blocking call from an I/O perspective so depending on your use case this might be a downside.
0006 ECHO string("juice: ") 0007 ECHO CV0($juice) 0008 ECHO string(" ") 0009 ECHO CV0($juice)
The third version uses CONCAT/FAST_CONCAT to create an intermediate string representation and as such might use more memory than the rope version.
0010 T1 = CONCAT string("juice: ") CV0($juice) 0011 T2 = FAST_CONCAT T1 string(" ") 0012 T1 = CONCAT T2 CV0($juice) 0013 ECHO T1
So ... what is the right thing to do here and why is it string interpolation?
String interpolation uses either a FAST_CONCAT in the case of echo "juice: $juice"; or highly optimised ROPE_* opcodes in the case of echo "juice: $juice $juice";, but most important it communicates the intent clearly and none of this has been bottle neck in any of the PHP applications I have worked with so far, so none of this actually matters.
String interpolation is a compile time thing. Granted, without OPcache the lexer will have to check for variables used in double quoted strings on every request, even if there aren't any, waisting CPU cycles, but honestly: The problem is not the double quoted strings, but not using OPcache!
However, there is one caveat: PHP up to 4 (and I believe even including 5.0 and maybe even 5.1, I don't know) did string interpolation at runtime, so using these versions ... hmm, I guess if anyone really still uses PHP 5, the same as above applies: The problem is not the double quoted strings, but the use of an outdated PHP version.
Update to the latest PHP version, enable OPcache and live happily ever after!
Das obige ist der detaillierte Inhalt vonZu doppeltes Anführungszeichen oder nicht, das ist hier die Frage!. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!