Petikan yang terlalu berganda atau tidak, itulah persoalannya!

王林
Lepaskan: 2024-08-16 16:34:49
asal
387 orang telah melayarinya

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-Zyklen sparen!

„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).

Was hat es mit dem Flaum auf sich?

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.
Salin selepas log masuk

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.
Salin selepas log masuk

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';
Salin selepas log masuk

.. 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 das ist bei jedem der Fall Glücklich, Fall abgeschlossen.

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, in 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

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 (
         
Salin selepas log masuk
Salin selepas log masuk

In diesem 3v4l.org-Snippet können wir das in Aktion sehen und damit spielen.

Der Parser

Der Parser nimmt diese Token und generiert daraus einen abstrakten Syntaxbaum. Eine AST-Darstellung des obigen Beispiels sieht so aus, wenn sie als JSON:
dargestellt wird

{ "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": "" } ] } ] }
Salin selepas log masuk

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, die beide zeigen Sie erhalten den AST eines bestimmten PHP-Codestücks.

Der Compiler

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):

  1. Verwenden Sie die vulcan Logic Dumper-Erweiterung. Es ist auch in 3v4l.org integriert
  2. Verwenden Sie phpdbg -p script.php, um die Opcodes auszugeben
  3. Oder verwenden Sie die INI-Einstellung opcache.opt_debug_level für OPcache, um die Opcodes auszudrucken
    • Ein Wert von 0x10000 gibt Opcodes vor der Optimierung aus
    • Ein Wert von 0x20000 gibt Opcodes nach der Optimierung aus
$ echo ' foo.php $ php -dopcache.opt_debug_level=0x10000 foo.php $_main: ... 0000 ECHO string("") 0001 RETURN int(1) 

Hypothese

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.

Was passiert zur Laufzeit?

Mal sehen, welche Opcodes PHP für die beiden verschiedenen Versionen erstellt.

Doppelte Anführungszeichen:


        
Salin selepas log masuk
0000 ECHO string("apple") 0001 RETURN int(1)
Salin selepas log masuk
Salin selepas log masuk

vs. einfache Anführungszeichen:


        
Salin selepas log masuk
0000 ECHO string("apple") 0001 RETURN int(1)
Salin selepas log masuk
Salin selepas log masuk

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 (
         
Salin selepas log masuk
Salin selepas log masuk

vs. einfache Anführungszeichen:

Line 1: T_OPEN_TAG (
        
Salin selepas log masuk

Die Token unterscheiden immer noch zwischen doppelten und einfachen Anführungszeichen, aber die Überprüfung des AST liefert 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, aber den Wert hat verwendet in beiden Fällen doppelte Anführungszeichen.

Neue Hypothese

Könnte es sein, dass die String-Interpolation tatsächlich zur Kompilierzeit erfolgt?

Lassen Sie es uns anhand eines etwas „anspruchsvolleren“ Beispiels überprüfen:


        
Salin selepas log masuk

Tokens für diese Datei sind:

T_OPEN_TAG (
        
Salin selepas log masuk

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.

Too double quote or not, that

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)
Salin selepas log masuk

This is different opcode than we had in our simple

Get to the point: should I concat or interpolate?

Let's have a look at these three different versions:


        
Salin selepas log masuk
  • the first version is using string interpolation
  • the second is using a comma separation (which AFAIK only works with echo and not with assigning variables or anything else)
  • and the third option uses string concatenation

The first opcode assigns the string "apple" to the variable $juice:

0000 ASSIGN CV0($juice) string("apple")
Salin selepas log masuk

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
Salin selepas log masuk

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)
Salin selepas log masuk

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
Salin selepas log masuk

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.

TLDR

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.

Final advice

Update to the latest PHP version, enable OPcache and live happily ever after!

Atas ialah kandungan terperinci Petikan yang terlalu berganda atau tidak, itulah persoalannya!. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

sumber:dev.to
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan
Tentang kita Penafian Sitemap
Laman web PHP Cina:Latihan PHP dalam talian kebajikan awam,Bantu pelajar PHP berkembang dengan cepat!