
Bei PHP-Mikrooptimierungen werden durch Ersetzen von doppelten Anführungszeichen durch einfache Anführungszeichen so viele Kopien beschädigt, dass es ziemlich problematisch ist, einen neuen Stream zu erstellen. Aber ich werde es versuchen.
In diesem Artikel wird es nur einen Benchmark geben, wo er ohne wäre, und der Schwerpunkt liegt auf der Analyse, wie er im Inneren angeordnet ist.
Haftungsausschluss
- Alles, was unten beschrieben wird, spart größtenteils Nanosekunden, und in der Praxis wird es nichts anderes tun, als die Zeit zu verlieren, die bei einer solchen Mikrooptimierung verloren geht. Dies gilt insbesondere für "Optimierungen" der Kompilierungszeit.
- Ich werde den Code schneiden und maximal ausgeben, wobei nur die Essenz übrig bleibt.
- Beim Schreiben eines Artikels habe ich PHP 7.2 verwendet
Notwendige Einführung
Eine Zeichenfolge in doppelten Anführungszeichen wird
in der Kompilierungsphase geringfügig anders verarbeitet als eine Zeichenfolge in einfachen Anführungszeichen.
Einfache Anführungszeichen werden wie folgt analysiert:
statement -> expr -> scalar -> dereferencable_scalar -> T_CONSTANT_ENCAPSED_STRING
Verdoppeln Sie also:
statement -> expr -> scalar -> '"' encaps_list '"' -> , ,
In Artikeln über PHP-Mikrooptimierungen wird sehr oft empfohlen, den
Druck nicht zu verwenden, da er langsamer als das
Echo ist . Mal sehen, wie sie sortiert sind.
Parsing-
Echo :
statement -> T_ECHO echo_expr_list -> echo_expr_list -> echo_expr -> expr
Analysedruck:
statement -> expr -> T_PRINT expr -> expr ( )
Das heißt, Im Allgemeinen wird das
Echo einen Schritt früher erkannt, und dieser Schritt ist, wie zu beachten ist, ziemlich schwierig.
Um die Aufmerksamkeit während des Artikels nicht noch einmal zu betonen, werden wir bedenken, dass in der Kompilierungsphase doppelte Anführungszeichen einfache Anführungszeichen verlieren und der
Druck das
Echo verliert. Vergessen wir auch nicht, dass es im schlimmsten Fall um Nanosekunden geht.
Nun, um nicht zweimal aufzustehen. Hier sind die Diff-Funktionen, die
Print und
Echo kompilieren:
1 - void zend_compile_print(znode *result, zend_ast *ast) 1 + void zend_compile_echo(zend_ast *ast) 2 2 { 3 3 zend_op *opline; 4 4 zend_ast *expr_ast = ast->child[0]; 5 5 6 6 znode expr_node; 7 7 zend_compile_expr(&expr_node, expr_ast); 8 8 9 9 opline = zend_emit_op(NULL, ZEND_ECHO, &expr_node, NULL); 10 - opline->extended_value = 1; 11 - 12 - result->op_type = IS_CONST; 13 - ZVAL_LONG(&result->u.constant, 1); 10 + opline->extended_value = 0; 14 11 }
Nun, Sie verstehen - sie sind in der Funktionalität identisch, aber
print gibt zusätzlich eine Konstante gleich 1 zurück. Ich denke, bei diesem Thema mit
print können Sie es für immer schließen und vergessen.
Einfache Linie, ohne Schnickschnack
Strings
echo 'Some string';
und
echo "Some string";
wird fast identisch in 2 (Haftungsausschluss P2) Token aufgeteilt.
T_ECHO: echo T_ENCAPSED_AND_WHITESPACE/T_CONSTANT_ENCAPSED_STRING: "Some string"
Darüber hinaus gibt es für einfache Anführungszeichen immer T_CONSTANT_ENCAPSED_STRING und für doppelte Anführungszeichen, wenn es so ist. Wenn in der Zeile ein Leerzeichen vorhanden ist, wird T_ENCAPSED_AND_WHITESPACE verwendet.
Die Opcodes sind einfach zu blamieren und absolut identisch:
line
Schlussfolgerungen
Wenn Sie in der Kompilierungsphase einige Prozessorzyklen speichern möchten, verwenden Sie für konstante Zeichenfolgen einfache Anführungszeichen.
Dynamische Linie
Es gibt 4 Optionen.
echo "Hello $name! Have a nice day!"; echo 'Hello '.$name.'! Have a nice day!'; echo 'Hello ', $name, '! Have a nice day!'; printf ('Hello %s! Have a nice day!', $name);
Für die erste Option:
T_ECHO: echo T_ENCAPSED_AND_WHITESPACE: Hello T_VARIABLE: $name T_ENCAPSED_AND_WHITESPACE: ! Have a nice day!
Für die zweite (auch für die dritte gibt es nur anstelle von Punkten Kommas):
T_ECHO: echo T_CONSTANT_ENCAPSED_STRING: 'Hello ' string: . T_VARIABLE: $name string: . T_CONSTANT_ENCAPSED_STRING: '! Have a nice day!'
Zum vierten:
T_STRING: printf T_CONSTANT_ENCAPSED_STRING: 'Hello %s! Have a nice day!' string: , T_VARIABLE: $name
Aber mit Opcodes wird alles viel unterhaltsamer.
Erster:
echo "Hello $name! Have a nice day!"; line
Zweitens:
echo 'Hello '.$name.'! Have a nice day!'; line
Drittens:
echo 'Hello ', $name, '! Have a nice day!'; line
Viertens:
printf ('Hello %s! Have a nice day!', $name); line
Der gesunde Menschenverstand sagt uns, dass die Option mit "printf" durch die ersten drei an Geschwindigkeit verlieren wird (zumal es am Ende immer noch das gleiche ECHO gibt), so dass wir es für Aufgaben belassen, bei denen eine Formatierung erforderlich ist, und wir werden uns in diesem Artikel nicht mehr daran erinnern.
Es scheint, dass die dritte Option die schnellste ist - drei Zeilen hintereinander ohne Verkettungen, seltsame ROPEs und die Erstellung zusätzlicher Variablen zu drucken. Aber nicht so einfach. Die Druckfunktion in PHP ist sicherlich nicht Rocket Science, aber es ist keineswegs eine banale C-shny-
Eingabe . Wen
kümmert es - der Ball löst sich beginnend mit
php_output_write in der
Datei main / output.c .
CONCAT. Hier ist alles einfach - wir konvertieren die Argumente bei Bedarf in Strings und erstellen mit fast
memcpy einen neuen
zend_string . Der einzige Nachteil ist, dass mit einer langen Kette von Verkettungen für jede Operation neue Zeilen erstellt werden, indem dieselben Bytes von Ort zu Ort verschoben werden.
Aber mit ROPE_INIT, ROPE_ADD und ROPE_END ist alles viel interessanter. Folgen Sie den Händen:
- ROPE_INIT (ext = 3, return = ~ 3, operands = 'Hello +')
Wir ordnen das "Seil" aus drei Slots (ext) zu, setzen den String 'Hello +' (Operanden) in Slot 0 und geben die temporäre Variable ~ 3 (return) zurück, die das "Seil" enthält. - ROPE_ADD (ext = 1, return = ~ 3, Operanden = ~ 3 ,! 0)
Wir setzen in den Schlitz 1 (ext) des "Seils" ~ 3 (Operanden) die Zeichenfolge 'Vasya', die aus der Variablen! 0 (Operanden) erhalten wird, und geben das "Seil" ~ 3 (return) zurück. - ROPE_END (ext = 2, return = ~ 2, operands = ~ 3, '% 21 + Have + a + nice + day% 21')
Wir setzen die Zeile '% 21 + Have + a + nice + day% 21' (Operanden) in Slot 2 (ext), danach erstellen wir einen zend_string der erforderlichen Größe und kopieren alle "Seil" -Slots nacheinander mit demselben Memcpy hinein .
Unabhängig davon ist zu beachten, dass bei Konstanten und temporären Variablen Links zu den Daten in den Slots platziert werden und kein unnötiges Kopieren erfolgt.
Meiner Meinung nach ziemlich elegant. :) :)
Lassen Sie uns Benchmarking. Als Quelldaten nehmen wir die Datei
zend_vm_execute.h (IMHO wird dies zutreffen) für
71.000 Zeilen und drucken sie auf 100 Arten für 100 Durchgänge, wobei das Minimum und das Maximum
gelöscht werden (jede Messung wurde 10 Mal gestartet, wobei die häufigste Option ausgewählt wurde):
<?php $file = explode("\n", file_get_contents("C:\projects\C\php-src\Zend\zend_vm_execute.h")); $out = []; for ($c = 0; $c < 100; $c++) { $start = microtime(true); ob_start(); $i = 0; foreach ($file as $line) { $i++;
Was messen wir? | Durchschnittliche Zeit in Sekunden |
---|
"Seil" | 0,0129 |
Mehrere ECHO | 0,0135 |
Verkettung | 0,0158 |
printf der Vollständigkeit halber | 0,0245 |
Schlussfolgerungen
- Bei Zeichenfolgen mit einfacher Ersetzung sind doppelte Anführungszeichen plötzlich optimaler als einfache Anführungszeichen mit Verkettung. Und je länger die Leitungen verwendet werden, desto größer ist die Verstärkung.
- Durch Kommas getrennte Argumente ... Es gibt viele Nuancen. Durch Messung ist es schneller als die Verkettung und langsamer als das „Seil“, aber es gibt zu viele „Variablen“, die mit der Eingabe / Ausgabe verbunden sind.
Fazit
Es fällt mir schwer, eine Situation zu finden, in der solche Mikrooptimierungen erforderlich sein können. Wenn Sie sich für diesen oder jenen Ansatz entscheiden, ist es sinnvoller, sich von anderen Prinzipien leiten zu lassen - beispielsweise von der Lesbarkeit des Codes oder dem von Ihrem Unternehmen verwendeten Codierungsstil.
Ich persönlich mag den Verkettungsansatz wegen des vyrviglazny-Aussehens nicht, obwohl er in einigen Fällen gerechtfertigt sein kann.
PS Wenn diese Art der Analyse interessant ist - lassen Sie es mich wissen -, gibt es noch viel mehr, das alles andere als immer eindeutig und offensichtlich ist: eine Reihe von VS-Objekten, für jedes VS, während VS für, Ihre Option ... :)
Eine kleine Erklärung aus dem Lesen von Kommentaren
Die HEREDOC-Syntax und die „komplexen Zeichenfolgen“ (wobei sich die Variablen in geschweiften Klammern befinden) sind dieselben Zeichenfolgen in doppelten Anführungszeichen und werden auf genau dieselbe Weise kompiliert.
Eine Mischung aus PHP mit HTML wie folgt:
<?php $name = 'Vasya';?>Hello <?=$name?>! Have a nice day!
Dies sind nur 3
Echos hintereinander.