Twig: acelere a geração de seus templates
Agência web » Notícias digitais » Twig: acelere a geração de seus templates

Twig: acelere a geração de seus templates

Recentemente, me perguntei para refletir sobre as soluções oferecidas pelo Twig para acessar as propriedades de um objeto ou array.

Acessando uma propriedade de um objeto

O Twig foi projetado para simplificar nossos templates, tanto em termos de código quanto em termos de limpeza. Também foi pensado para permitir aos integradores, pessoas que nem todas possuem conhecimento de desenvolvimento, fácil acesso às propriedades de um objeto ou outros. Isso graças a uma sintaxe simplificada.

Só então, sendo um desenvolvedor acima de tudo, me perguntei como o twig estava fazendo para determinar qual método de um objeto deveria ser chamado.

Sintaxe do galho

No meu código a seguir, assumirei que estou usando uma classe como abaixo.

1
2
3
4
5
6
7
8
9
10
11
12
13
classe objeto
{
privado $Nome;
público $nome de usuário;
público função getNome() {
retorno $ This->nome;
}
público função obter nome de usuário() {
retorno $ This->nome de usuário;
}
}

É assim que chamarei meu modelo de um controlador Symfony.

1
2
3
público função indexAção() {
retorno ordem("objeto" => $objeto);
}

Até agora, tudo está claro. Meu objeto se parece exatamente com os objetos que posso usar em meus projetos.

Analisando declarações no Twig

1
{{ object.name }}

A partir de agora veremos como o Twig trabalha com nossas chamadas. Aqui, pedimos ao Twig que tome o valor nome do meu objeto, exceto que para Twig que é apenas uma simples chamada PHP no final, esta variável é inacessível. Twig, portanto, adicionou um proxy para abstrair e ver quais propriedades e métodos estão disponíveis.

Twig, portanto, pedirá na ordem abaixo para fazer verificações no objeto.

  1. Veja se objeto é uma matriz e se nome é uma chave;
  2. Veja se objeto é um objeto e se nome é um atributo acessível;
  3. Veja se objeto é um objeto e se nome é um método;
  4. Veja se objeto é um objeto e se getNome é um método;
  5. Veja se objeto é um objeto e se é nome é um método.
    Aqui, com a notação que usamos, tivemos que esperar a 4ª condição chegar ao nosso elemento. Porque nome não é um atributo acessível, nem um método.

    1
    {{ object.username }}

Neste caso, estamos tentando acessar nome de usuário. Este atributo é um atributo público (no Symfony, raramente encontrei este caso). Temos que esperar pela 2ª condição.

1
{{ object.getName() }}

Em nosso terceiro caso, tento chamar meu método diretamente. Obtenho meu resultado da terceira condição, que é uma condição mais rápida.

1
{{ object.getUsername() }}

Em nosso quarto e último caso, tento usar meu método diretamente. Eu obtenho meu resultado da terceira condição. Nesse caso, coloco uma condição adicional para acessar meu valor.

Interpretando templates do Twig

Quando olhei para esse detalhe, pensei em como os desenvolvedores do Twig poderiam ter feito o cache e a compilação dos templates. Não demorei muito para chegar à conclusão de que com a pouca informação e a liberdade que o gerenciador de templates oferece, nossos arquivos são simplesmente transcritos para PHP de forma semelhante ao que poderíamos fazer totalmente. Você também pode ver por si mesmo procurando em sua pasta de cache.

1
2
{# ramificação do modelo #}
{{ object.name }}
Modelo interpretado em PHP
1
echo twig_escape_filter($this->env, $this->getAttribute((isset($context["object"]) ? $context["object"] : $this->getContext($context, "object")), “nome”), “html”, nulo, verdadeiro);

O primeiro bloco corresponde ao que anotei em meu modelo de twig, o segundo bloco corresponde à versão traduzida que encontrei na pasta de cache.

Notamos que a ramificação foi traduzida para PHP, mas nenhum elemento permitiu prever qual método deve ser chamado exatamente. O método branch_escape_filter pode ser comparado a um proxy. É neste método que vamos determinar como acessamos o atributo.

Conclusão

Embora os templates twig sejam automaticamente armazenados em cache pelo Symfony, apenas a versão do PHP é mantida, mas sem interpretação do que você deseja recuperar. Teoricamente, portanto, há aqui meios para otimizar as chamadas e o tempo de geração de nossos modelos, pois a verificação é realizada a cada chamada.

referência

Ainda queria ter uma ideia dos ganhos que podem ser obtidos chamando os métodos ao invés de " aliás ".

No primeiro caso, eu chamo um template que irá chamar 10 vezes o mesmo objeto que por sua vez chama 25 aliases. Isso representa 250 chamadas. Os resultados são ampliados pelo loop de 10 para permitir cálculos precisos quanto ao ganho de desempenho.

Em segundo lugar, chamo um modelo que chamará o mesmo objeto 10 vezes e que, por sua vez, chamará 25 métodos (sempre por meio do mesmo proxy dos aliases). Isso é 250 novamente.

Fiz a chamada desses templates 5 vezes cada.

Observe que todas as chamadas para o modelo que fazem chamadas para métodos são mais rápidas. Ao fazer as médias, notamos que o modelo usando aliases é mais longo em 54,6 milissegundos (197.4 – 142.8).

Fazendo um cálculo rápido, notamos que se reduzirmos a um caso geral, o template que usa chamadas a métodos é mais rápido em média nos mesmos dados em aproximadamente 26.7%. Isso pode ser interessante ao fazer muitas chamadas a objetos.

Este segundo artigo segue um primeiro post dando soluções rápidas para otimizar a geração de templates. É fruto de otimizações já utilizadas em sites em produção que tinham uma taxa de latência muito alta.

usamos todos inclui de Galho para mudar ou fatorar nossos pontos de vista. Mas talvez você nunca tenha entendido porque tínhamos a capacidade de passar parâmetros, enquanto um include básico herda variáveis ​​do contexto atual.

1
{% incluir “ProjectMyBundle:Sub:template.html.twig” %}

Frequentemente usamos essa notação. Neste caso, o include dará uma cópia de todas as nossas variáveis ​​para o nosso template. Isso nem sempre é necessário e erramos ao copiar todas as nossas variáveis.

Juros da opção "única"

Por muito tempo me perguntei qual era o sentido dessa opção. Além disso, deve-se dizer que a documentação não dá muita informação. Você pode dar uma olhada na documentação do Twig includes. Dá pouco elemento, mas dá especialmente uma desvantagem e nenhuma vantagem: prescindir de certas variáveis. Visto desta forma, não é rentável; por que eu deveria fazer sem algumas variáveis.

Vamos implementar nossos includes! Digamos que nosso template base tenha 5 variáveis ​​e eu incluo um template que usa apenas uma dessas variáveis, essa é a notação que será preferível.

1
{% incluir "ProjectMyBundle:Sub:template.html.twig" com {"object": myVar} apenas %}

Desta forma, apenas uma variável "objeto" estará disponível em meu modelo. Isso limita a cópia de variáveis ​​inúteis e, portanto, de alocação de memória (economizando tempo e consumo de memória).

Código e casos de uso

1
2
3
4
5
6
// Controlador
// Aqui o gera um template passando uma variável imponente (uma coleção) contendo todos os objetos para uma determinada tabela
público função testeAção() {
$objetos = $ This->container->get(“doctrine.orm.default_entity_manager”)->getRepository(“ProjectMyBundle: Teste”)->encontrarTodos();
retorno ordem("Unid" => $objetos);
}

Fazemos um loop em nossa coleção e damos um modelo a cada iteração da coleção para o modelo. Neste caso, cada vez que chamamos a integração de um template, todas as variáveis ​​são copiadas assim como as passadas com a opção "com". Em nosso primeiro caso, poderíamos muito bem imaginar acessar nossa coleção (objetos), bem como nossa iteração atual (objeto).

1
2
3
4
5
{#Modelo 1#}
{% para objeto em objetos %}
{% incluir "ProjectMyBundle:Sub:template.html.twig" com {"object": object} %}
{% fim %}

Em nosso segundo caso, eu ativo a opção que permite copiar apenas as variáveis ​​passadas como parâmetros. Fácil ?

1
2
3
4
5
{#Modelo 2#}
{% para objeto em objetos %}
{% incluir "ProjectMyBundle:Sub:template.html.twig" com {"object": object} apenas %}
{% fim %}

referência

Realizei os testes com os templates e o código dado na parte acima. Realizei com 5 iterações de cada template, lembrando de esvaziar o cache antes de cada primeiro teste.

Com este gráfico, podemos ver que o carregamento geralmente é mais longo para quem não usa a opção . A diferença tende a diminuir após o armazenamento em cache. Isso se deve ao fato de que meu modelo é pequeno e poucas variáveis ​​são usadas. Em casos mais aplicados, há ganhos de até 30%.

Aqui, se fizermos a média dos valores, chegamos a uma diferença média de 9 ms (48,6 – 39,6 = 9). Podemos, portanto, calcular um ganho aproximado de 20%, mesmo que isso seja colocado em perspectiva no nosso caso, pois o primeiro tiro é terrivelmente longo sem o uso de “ ".

★ ★ ★ ★ ★