Twig: Beschleunigung der Generierung seiner Vorlagen
Kürzlich habe ich mich gefragt, welche Lösungen Twig bietet, um auf die Eigenschaften eines Objekts oder eines Arrays zuzugreifen.
Zugriff auf eine Eigenschaft eines Objekts
Twig wurde entwickelt, um unsere Vorlagen zu vereinfachen, sowohl in Bezug auf den Code als auch in Bezug auf die Sauberkeit. Es wurde auch entwickelt, um Integratoren, Personen, die nicht alle über Entwicklungskenntnisse verfügen, einen einfachen Zugriff auf die Eigenschaften eines Objekts oder anderer zu ermöglichen. Dies dank einer vereinfachten Syntax.
Erst dann stellte ich mir als Entwickler vor allem die Frage, wie es Twig geht, zu bestimmen, welche Methode eines Objekts aufgerufen werden soll.
Zweig-Syntax
In meinem folgenden Code gehe ich davon aus, dass ich eine Klasse wie unten verwende.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
Klasse Betreff
{
privat $Name;
Öffentlichkeit $Benutzername;
Öffentlichkeit Funktion getName() {
Rückkehr $ This->Name;
}
Öffentlichkeit Funktion getBenutzername() {
Rückkehr $ This->Benutzername;
}
}
|
So werde ich mein Template von einem Symfony-Controller aus aufrufen.
1
2
3
|
Öffentlichkeit Funktion indexAktion() {
Rückkehr Array("Objekt" => $objekt);
}
|
Soweit ist alles klar. Mein Objekt sieht genauso aus wie die Objekte, die ich in meinen Projekten verwenden kann.
Parsing-Deklarationen in Twig
1
|
{{ object.name }}
|
Von nun an werden wir sehen, wie Twig mit unseren Anrufen arbeitet. Hier bitten wir Twig, den Wert zu nehmen Name meines Objekts, außer dass für Twig, das am Ende nur ein einfacher PHP-Aufruf ist, diese Variable nicht zugänglich ist. Twig hat daher einen Proxy hinzugefügt, um zu abstrahieren und zu sehen, welche Eigenschaften und Methoden verfügbar sind.
Twig wird Sie daher in der folgenden Reihenfolge bitten, das Objekt zu überprüfen.
- Sehen ob Objekt ist ein Array und wenn Name ist ein Schlüssel;
- Sehen ob Objekt ein Objekt ist und wenn Name ist ein zugängliches Attribut;
- Sehen ob Objekt ein Objekt ist und wenn Name ist eine Methode;
- Sehen ob Objekt ein Objekt ist und wenn getName ist eine Methode;
- Sehen ob Objekt ein Objekt ist und wenn ist Name ist eine Methode.
Hier mussten wir bei der von uns verwendeten Notation warten, bis die 4. Bedingung bei unserem Element ankommt. Weil Name ist weder ein zugängliches Attribut noch eine Methode.1{{ object.username }}
In diesem Fall versuchen wir, darauf zuzugreifen Benutzername. Dieses Attribut ist ein öffentliches Attribut (in Symfony ist mir dieser Fall selten begegnet). Wir müssen auf die 2. Bedingung warten.
1
|
{{ object.getName() }}
|
In unserem dritten Fall versuche ich, meine Methode direkt aufzurufen. Ich erhalte mein Ergebnis aus der dritten Bedingung, die eine schnellere Bedingung ist.
1
|
{{ object.getUsername() }}
|
In unserem vierten und letzten Fall versuche ich, meine Methode direkt anzuwenden. Mein Ergebnis erhalte ich aus der dritten Bedingung. In diesem Fall habe ich eine zusätzliche Bedingung gestellt, um auf meinen Wert zuzugreifen.
Interpretieren von Twig-Vorlagen
Als ich mir dieses Detail ansah, dachte ich darüber nach, wie die Entwickler von Twig das Caching und die Kompilierung der Templates hätten bewerkstelligen können. Es dauerte nicht lange, bis ich zu dem Schluss kam, dass unsere Dateien mit den wenigen Informationen und der Freiheit, die der Vorlagenmanager bietet, einfach in PHP transkribiert werden, ähnlich wie wir es könnten. Sie können sich auch selbst davon überzeugen, indem Sie in Ihrem Cache-Ordner nachsehen.
1
2
|
{# Vorlagenzweig #}
{{ object.name }}
|
1
|
echo twig_escape_filter($this->env, $this->getAttribute((isset($context["object"]) ? $context["object"] : $this->getContext($context, "object")), „name“), „html“, null, wahr);
|
Der erste Block stimmt mit dem überein, was ich in meiner Zweigvorlage notiert habe, der zweite Block stimmt mit der übersetzten Version überein, die ich im Cache-Ordner gefunden habe.
Wir stellen fest, dass die Verzweigung in PHP übersetzt wurde, aber kein Element erlaubte, vorherzusagen, welche Methode genau aufgerufen werden sollte. Die Methode branch_escape_filter könnte mit einem Proxy verglichen werden. In dieser Methode bestimmen wir, wie wir auf das Attribut zugreifen.
Fazit
Obwohl Twig-Templates automatisch von Symfony zwischengespeichert werden, wird nur die PHP-Version beibehalten, jedoch ohne Interpretation dessen, was Sie abrufen möchten. Theoretisch besteht hier also die Möglichkeit Aufrufe und die Generierungszeit unserer Templates zu optimieren, da die Verifizierung bei jedem Aufruf durchgeführt wird.
Benchmark
Ich wollte immer noch eine Vorstellung von den Gewinnen haben, die durch Aufrufen der Methoden erzielt werden können, anstatt " alias ".
In einem ersten Fall rufe ich eine Vorlage auf, die 10 Mal dasselbe Objekt aufruft, das wiederum 25 Aliase aufruft. Dies entspricht 250 Anrufen. Die Ergebnisse werden durch die Schleife von 10 vergrößert, um genaue Berechnungen hinsichtlich des Leistungsgewinns zu ermöglichen.
Zweitens rufe ich ein Template auf, das 10 Mal dasselbe Objekt aufruft und das wiederum 25 Methoden aufruft (immer über denselben Proxy wie für die Aliase). Das sind wieder 250.
Ich habe diese Vorlagen jeweils 5 Mal aufgerufen.
Beachten Sie, dass alle Aufrufe der Vorlage, die Aufrufe von Methoden vornehmen, schneller sind. Wenn wir die Durchschnittswerte nehmen, stellen wir fest, dass die Vorlage, die Aliase verwendet, um 54,6 Millisekunden länger ist (197.4 – 142.8).
Durch eine schnelle Berechnung stellen wir fest, dass, wenn wir es auf einen allgemeinen Fall reduzieren, die Vorlage, die Aufrufe von Methoden verwendet, bei denselben Daten im Durchschnitt um etwa 26.7 % schneller ist. Dies kann interessant sein, wenn viele Aufrufe von Objekten durchgeführt werden.
Dieser zweite Artikel folgt auf einen ersten Beitrag, der schnelle Lösungen zur Optimierung der Generierung von Vorlagen bietet. Es ist das Ergebnis einer Optimierung, die bereits an Standorten in der Produktion verwendet wurde, die eine zu hohe Latenzrate hatten.
Wir nutzen alle Dazu gehören de Zweig unsere Ansichten zu verschieben oder zu beeinflussen. Aber vielleicht haben Sie nie verstanden, warum wir die Möglichkeit hatten, Parameter zu übergeben, wenn ein grundlegendes Include Variablen aus dem aktuellen Kontext erbt.
1
|
{% das „ProjectMyBundle:Sub:template.html.twig“ %}
|
Oft verwenden wir diese Notation. In diesem Fall gibt das Include eine Kopie aller unserer Variablen an unser Template weiter. Dies ist nicht immer notwendig, und es ist falsch, alle unsere Variablen zu kopieren.
Interesse der „einzigen“ Option
Ich habe mich lange gefragt, was der Sinn dieser Option ist. Außerdem muss gesagt werden, dass die Dokumentation nicht viele Informationen gibt. Sie können einen Blick auf die Twig-includes-Dokumentation werfen. Es gibt wenig Element, aber es gibt vor allem einen Nachteil und keinen Vorteil: auf bestimmte Variablen zu verzichten. So gesehen ist es nicht profitabel; warum ich auf einige Variablen verzichten sollte.
Lassen Sie uns unsere Includes implementieren! Nehmen wir an, unsere Basisvorlage hat 5 Variablen und ich füge eine Vorlage hinzu, die nur eine dieser Variablen verwendet. Dies ist die Notation, die bevorzugt wird.
1
|
{% das "ProjectMyBundle:Sub:template.html.twig" nur mit {"object": myVar} %}
|
Auf diese Weise ist in meiner Vorlage nur eine "Objekt"-Variable verfügbar. Dies begrenzt das Kopieren nutzloser Variablen und damit die Speicherzuweisung (Einsparung von Zeit und Speicherverbrauch).
Code und Anwendungsfälle
1
2
3
4
5
6
|
// Controller
// Hier wird eine Vorlage generiert, indem eine imposante Variable (eine Sammlung) übergeben wird, die alle Objekte für eine bestimmte Tabelle enthält
Öffentlichkeit Funktion testAktion() {
$Objekte = $ This->Behälter->holen(„doctrine.orm.default_entity_manager“)->getRepository(„ProjectMyBundle:Test“)->findAll();
Rückkehr Array("Artikel" => $Objekte);
}
|
Wir durchlaufen unsere Sammlung und geben der Vorlage bei jeder Iteration der Sammlung eine Vorlage. In diesem Fall werden bei jedem Aufruf zur Einbindung eines Templates alle Variablen kopiert sowie die mit übergebenen die "mit"-Option. In unserem ersten Fall könnten wir uns sehr gut vorstellen, sowohl auf unsere Sammlung (Objekte) als auch auf unsere aktuelle Iteration (Objekt) zuzugreifen.
1
2
3
4
5
|
{#Vorlage 1#}
{% für Objekt in Objekten %}
{% das "ProjectMyBundle:Sub:template.html.twig" mit {"object": object} %}
{% Endefür %}
|
In unserem zweiten Fall aktiviere ich die Option einzige Dadurch können Sie nur die als Parameter übergebenen Variablen kopieren. Einfach ?
1
2
3
4
5
|
{#Vorlage 2#}
{% für Objekt in Objekten %}
{% das "ProjectMyBundle:Sub:template.html.twig" nur mit {"object": object} %}
{% Endefür %}
|
Benchmark
Ich habe die Tests mit den im obigen Teil angegebenen Vorlagen und dem Code durchgeführt. Ich habe 5 Iterationen jeder Vorlage durchgeführt und daran gedacht, den Cache vor jedem ersten Test zu leeren.
Mit diesem Diagramm können wir sehen, dass das Laden für diejenigen, die die Option nicht verwenden, im Allgemeinen länger ist einzige. Der Unterschied verringert sich tendenziell nach dem Caching. Dies liegt daran, dass meine Vorlage klein ist und nur wenige Variablen verwendet werden. In stärker angewandten Fällen gibt es Gewinne von bis zu 30 %.
Mittelt man hier die Werte, kommt man auf eine durchschnittliche Differenz von 9 ms (48,6 – 39,6 = 9). Wir können daher einen ungefähren Gewinn von 20% berechnen, auch wenn dies in unserem Fall zu relativieren ist, da der erste Schuss ohne den Einsatz von „ einzige ".