Twig: fremskynd genereringen af dens skabeloner
For nylig bad jeg mig selv om at reflektere over de løsninger, som Twig tilbyder for at få adgang til egenskaberne af et objekt eller et array.
Adgang til en egenskab ved et objekt
Twig er designet til at forenkle vores skabeloner, både med hensyn til kode og med hensyn til renlighed. Det blev også designet til at give integratorer, folk som ikke alle har udviklingsviden, nem adgang til egenskaberne for et objekt eller andre. Dette takket være en forenklet syntaks.
Først da, som udvikler frem for alt, stillede jeg mig selv spørgsmålet om, hvordan twig klarede sig for at bestemme, hvilken metode af et objekt der skulle kaldes.
Kvist syntaks
I min følgende kode vil jeg antage, at jeg bruger en klasse som nedenfor.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
klasse Object
{
private $navn;
offentlige $brugernavn;
offentlige funktion fåNavn() {
afkast $ dette->navn;
}
offentlige funktion få Brugernavn() {
afkast $ dette->brugernavn;
}
}
|
Sådan vil jeg kalde min skabelon fra en Symfony-controller.
1
2
3
|
offentlige funktion indeksAktion() {
afkast matrix("objekt" => $objekt);
}
|
Indtil videre er alt klart. Mit objekt ligner præcis de objekter jeg kan bruge i mine projekter.
Parseerklæringer i Kvist
1
|
{{ object.name }}
|
Fra nu af vil vi se, hvordan Twig fungerer med vores opkald. Her beder vi Twig om at tage værdien navn af mit objekt, bortset fra at for Twig, som kun er et simpelt PHP-kald i sidste ende, er denne variabel utilgængelig. Twig har derfor tilføjet en proxy for at abstrahere og se hvilke egenskaber og metoder der findes.
Twig vil derfor i nedenstående rækkefølge bede om at foretage kontrol af genstanden.
- Se om objekt er et array og hvis navn er en nøgle;
- Se om objekt er en genstand og hvis navn er en tilgængelig egenskab;
- Se om objekt er en genstand og hvis navn er en metode;
- Se om objekt er en genstand og hvis fåNavn er en metode;
- Se om objekt er en genstand og hvis er Navn er en metode.
Her måtte vi med den notation, vi brugte, vente på, at 4. betingelse nåede frem til vores element. Fordi navn er ikke en tilgængelig egenskab eller en metode.1{{ object.username }}
I dette tilfælde forsøger vi at få adgang brugernavn. Denne attribut er en offentlig attribut (i Symfony stødte jeg sjældent på dette tilfælde). Vi må vente på 2. betingelse.
1
|
{{ object.getName() }}
|
I vores tredje tilfælde forsøger jeg at kalde min metode direkte. Jeg får mit resultat fra den tredje tilstand, som er en hurtigere tilstand.
1
|
{{ object.getUsername() }}
|
I vores fjerde og sidste tilfælde forsøger jeg at bruge min metode direkte. Jeg får mit resultat fra den tredje betingelse. I dette tilfælde sætter jeg en ekstra betingelse for at få adgang til min værdi.
Tolkning af Twig skabeloner
Da jeg så på denne detalje, tænkte jeg på, hvordan udviklerne af Twig kunne have lavet cachen og kompileringen af skabelonerne. Det tog ikke lang tid, før jeg kom til den konklusion, at med den lille information og den frihed, som skabelonmanageren tilbyder, bliver vores filer simpelthen transskriberet til PHP på samme måde, som vi helt kunne gøre. Du kan også selv se ved at kigge i din cache-mappe.
1
2
|
{# Skabelongren #}
{{ object.name }}
|
1
|
echo twig_escape_filter($this->env, $this->getAttribute((isset($context["objekt"]) ? $context["objekt"] : $this->getContext($context, "objekt")), "navn"), "html", null, sand);
|
Den første blok matcher det, jeg noterede i min kvistskabelon, den anden blok matcher den oversatte version, jeg fandt i cache-mappen.
Vi bemærker, at grenen er blevet oversat til PHP, men at intet element har tilladt den at forudsige, hvilken metode der skal kaldes nøjagtigt. Metoden branch_escape_filter kan sammenlignes med en proxy. Det er i denne metode, vi vil bestemme, hvordan vi får adgang til attributten.
Konklusion
Selvom kvistskabeloner automatisk cachelagres af Symfony, er det kun PHP-versionen, der opbevares, men uden fortolkning af, hvad du vil hente. I teorien er der derfor her midlerne til at optimere opkald og genereringstiden for vores skabeloner, fordi verifikationen udføres ved hvert opkald.
benchmark
Jeg ville stadig gerne have en idé om de gevinster, der kan opnås ved at kalde metoderne frem for " alias '.
I et første tilfælde kalder jeg en skabelon, som kalder 10 gange det samme objekt, som igen kalder 25 aliaser. Det svarer til 250 opkald. Resultaterne forstørres med løkken på 10 for at tillade nøjagtige beregninger af ydeevneforstærkningen.
For det andet kalder jeg en skabelon, som kalder det samme objekt 10 gange, og som igen kalder 25 metoder (altid via samme proxy som for aliaserne). Det er 250 igen.
Jeg kaldte disse skabeloner 5 gange hver.
Bemærk, at alle opkald til skabelonen, der foretager opkald til metoder, er hurtigere. Ved at tage gennemsnittet bemærker vi, at skabelonen, der bruger aliaser, er længere med 54,6 millisekunder (197.4 – 142.8).
Ved at lave en hurtig beregning bemærker vi, at hvis vi reducerer det til et generelt tilfælde, er skabelonen, der bruger opkald til metoder, hurtigere i gennemsnit på de samme data med cirka 26.7 %. Dette kan være interessant, når du foretager mange opkald til objekter.
Denne anden artikel følger et første indlæg, der giver hurtige løsninger til at optimere genereringen af skabeloner. Det er frugten af optimering, der allerede er brugt på websteder i produktionen, som havde en for høj latenstid.
Vi bruger alle omfatter de Twig at ændre eller faktorisere vores synspunkter. Men måske har du aldrig forstået, hvorfor vi havde evnen til at videregive parametre, mens en grundlæggende inkluderer arver variabler fra den aktuelle kontekst.
1
|
{% omfatter "ProjectMyBundle:Sub:template.html.twig" %}
|
Ofte bruger vi denne notation. I dette tilfælde vil include give en kopi af alle vores variabler til vores skabelon. Dette er ikke altid nødvendigt, og vi tager fejl af at kopiere alle vores variabler.
Interesse for den "eneste" mulighed
Jeg spekulerede længe på, hvad der var meningen med denne mulighed. Desuden skal det siges, at dokumentationen ikke giver meget information. Du kan tage et kig på kvisten inkluderer dokumentation. Det giver lidt element, men det giver især en ulempe og ingen fordel: at undvære visse variabler. Set på denne måde er det ikke rentabelt; hvorfor jeg skulle undvære nogle variabler.
Lad os implementere vores inkluderer! Lad os sige, at vores basisskabelon har 5 variabler, og jeg inkluderer en skabelon, der kun bruger en af disse variabler, det er den notation, der vil være at foretrække.
1
|
{% omfatter "ProjectMyBundle:Sub:template.html.twig" med kun {"object": myVar} %}
|
På denne måde vil kun en "objekt" variabel være tilgængelig i min skabelon. Dette begrænser kopieringen af ubrugelige variabler og derfor af hukommelsesallokering (sparer tid og hukommelsesforbrug).
Kode og bruge cases
1
2
3
4
5
6
|
// Controller
// Her genererer den en skabelon ved at sende en imponerende variabel (en samling), der indeholder alle objekterne for en given tabel
offentlige funktion testAktion() {
$objekter = $ dette->container->hent("doctrine.orm.default_entity_manager")->getRepository("ProjectMyBundle:Test")->findAlle();
afkast matrix("genstande" => $objekter);
}
|
Vi sløjfer over vores samling, og vi giver en skabelon hver iteration af samlingen til skabelonen. I dette tilfælde, hver gang vi opfordrer til integration af en skabelon, kopieres alle variabler såvel som dem, der er bestået med muligheden "med".. I vores første tilfælde kunne vi godt forestille os at få adgang til vores samling (objekter) såvel som vores nuværende iteration (objekt).
1
2
3
4
5
|
{#Skabelon 1#}
{% forum objekt i objekter %}
{% omfatter "ProjectMyBundle:Sub:template.html.twig" med {"object": object} %}
{% endfor %}
|
I vores andet tilfælde aktiverer jeg muligheden kun som giver dig mulighed for kun at kopiere de variabler, der sendes som parametre. Let ?
1
2
3
4
5
|
{#Skabelon 2#}
{% forum objekt i objekter %}
{% omfatter "ProjectMyBundle:Sub:template.html.twig" med kun {"object": object} %}
{% endfor %}
|
benchmark
Jeg udførte testene med skabelonerne og koden givet i delen ovenfor. Jeg udførte med 5 iterationer af hver skabelon, og huskede at tømme cachen før hver første test.
Med denne graf kan vi se, at belastningen generelt er længere for dem, der ikke bruger muligheden kun. Forskellen har en tendens til at blive mindre efter caching. Det skyldes, at min skabelon er lille, og der bruges få variabler. I mere anvendte tilfælde er der gevinster på op til 30 %.
Her når vi gennemsnit af værdierne, når vi en gennemsnitlig forskel på 9 ms (48,6 – 39,6 = 9). Vi kan derfor beregne en tilnærmet gevinst på 20%, selvom dette skal perspektiveres i vores tilfælde, da det første skud er frygteligt langt uden brug af " kun '.