Twig: ускорьте генерацию своих шаблонов
Недавно я попросил себя подумать о решениях, предлагаемых Twig для доступа к свойствам объекта или массива.
Доступ к свойству объекта
Twig был разработан, чтобы упростить наши шаблоны как с точки зрения кода, так и с точки зрения чистоты. Он также был разработан, чтобы позволить интеграторам, людям, которые не все имеют знания в области разработки, легкий доступ к свойствам объекта или другим. Это благодаря упрощенному синтаксису.
Только потом, будучи прежде всего разработчиком, я задал себе вопрос, как у twig обстоят дела с определением, какой метод объекта следует вызывать.
Синтаксис ветки
В моем следующем коде я предполагаю, что использую класс, как показано ниже.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
класс объект
{
частная $имя;
что такое варган? $имя пользователя;
что такое варган? функция GetName() {
возвращение $ Этой->имя;
}
что такое варган? функция получить имя пользователя() {
возвращение $ Этой->имя пользователя;
}
}
|
Вот как я буду вызывать свой шаблон из контроллера Symfony.
1
2
3
|
что такое варган? функция индексДействие() {
возвращение массив("объект" => $объект);
}
|
Пока все ясно. Мой объект выглядит точно так же, как объекты, которые я могу использовать в своих проектах.
Разбор объявлений в Twig
1
|
{{ object.name }}
|
С этого момента мы увидим, как Twig работает с нашими звонками. Здесь мы просим Twig принять значение имя моего объекта, за исключением того, что для Twig, который в конце концов является простым вызовом PHP, эта переменная недоступна. Поэтому Twig добавил прокси для абстрагирования и просмотра доступных свойств и методов.
Поэтому Twig будет запрашивать проверку объекта в порядке, указанном ниже.
- Видишь ли, если объект это массив и если имя является ключом;
- Видишь ли, если объект является объектом, и если имя является доступным атрибутом;
- Видишь ли, если объект является объектом, и если имя это метод;
- Видишь ли, если объект является объектом, и если GetName это метод;
- Видишь ли, если объект является объектом, и если Это имя это метод.
Здесь, с используемой нами нотацией, нам пришлось ждать, пока 4-е условие не достигнет нашего элемента. Потому что имя не является ни доступным атрибутом, ни методом.1{{ object.username }}
В данном случае мы пытаемся получить доступ username. Этот атрибут является общедоступным атрибутом (в Symfony я редко сталкивался с таким случаем). Мы должны дождаться 2-го условия.
1
|
{{ object.getName() }}
|
В нашем третьем случае я пытаюсь вызвать свой метод напрямую. Я получаю свой результат из третьего условия, которое является более быстрым условием.
1
|
{{ object.getUsername() }}
|
В нашем четвертом и последнем случае я пытаюсь использовать свой метод напрямую. Я получаю результат из третьего условия. В этом случае я ставлю дополнительное условие для доступа к моему значению.
Интерпретация шаблонов Twig
Когда я посмотрел на эту деталь, я подумал о том, как разработчики Twig могли сделать кеширование и компиляцию шаблонов. Мне не потребовалось много времени, чтобы прийти к выводу, что с небольшим количеством информации и свободой, которую предлагает менеджер шаблонов, наши файлы просто транскрибируются в PHP аналогично тому, что мы могли бы сделать полностью. Вы также можете убедиться в этом сами, заглянув в папку с кешем.
1
2
|
{# Ветка шаблона #}
{{ object.name }}
|
1
|
echo twig_escape_filter($this->env, $this->getAttribute((isset($context["объект"]) ? $context["объект"] : $this->getContext($context, "объект")), «имя»), «html», null, true);
|
Первый блок соответствует тому, что я отметил в моем шаблоне ветки, второй блок соответствует переведенной версии, которую я нашел в папке кеша.
Мы отмечаем, что ветвь была переведена на PHP, но ни один элемент не позволил предсказать, какой именно метод должен быть вызван. Метод branch_escape_filter можно сравнить с прокси. Именно в этом методе мы определим, как мы получаем доступ к атрибуту.
Заключение
Хотя шаблоны веток автоматически кэшируются Symfony, сохраняется только версия PHP, но без интерпретации того, что вы хотите получить. Теоретически поэтому здесь есть средства для оптимизации вызовов и времени генерации наших шаблонов, поскольку проверка выполняется при каждом вызове.
эталонный тест
Я все еще хотел иметь представление о преимуществах, которые можно получить, вызывая методы, а не " псевдоним .
В первом случае я вызываю шаблон, который будет вызывать 10 раз один и тот же объект, который, в свою очередь, вызывает 25 псевдонимов. Это соответствует 250 вызовам. Результаты увеличиваются в 10 раз, чтобы обеспечить точные расчеты прироста производительности.
Во-вторых, я вызываю шаблон, который будет вызывать один и тот же объект 10 раз и который, в свою очередь, вызывает 25 методов (всегда через тот же прокси, что и для псевдонимов). Это снова 250.
Я сделал вызов этих шаблонов по 5 раз каждый.
Обратите внимание, что все вызовы шаблона, вызывающие вызовы методов, выполняются быстрее. Взяв средние значения, мы замечаем, что шаблон с использованием псевдонимов длиннее на 54,6 миллисекунды (197.4 – 142.8).
Делая быстрый расчет, мы замечаем, что если свести его к общему случаю, то шаблон с использованием вызовов методов работает быстрее в среднем на тех же данных примерно на 26.7%. Это может быть интересно при выполнении большого количества обращений к объектам.
Эта вторая статья следует за первой публикацией, предлагающей быстрые решения для оптимизации создания шаблонов. Это результат оптимизации, которая уже использовалась на рабочих сайтах со слишком высокой задержкой.
Мы используем все включает в себя de Веточка чтобы изменить или изменить наши взгляды. Но, возможно, вы никогда не понимали, почему у нас была возможность передавать параметры, когда базовое включение наследует переменные из текущего контекста.
1
|
{% включают «ProjectMyBundle:Sub:template.html.twig» %}
|
Часто мы используем это обозначение. В этом случае включение даст копию всех наших переменных в наш шаблон. Это не всегда необходимо, и мы ошибаемся, копируя все наши переменные.
Интерес «единственного» варианта
Я долго думал, в чем смысл этого варианта. Кроме того, нужно сказать, что документация не дает много информации. Вы можете ознакомиться с документацией по Twig. Это дает мало элемента, но дает особенно недостаток, а не преимущество: обходиться без определенных переменных. С этой точки зрения это невыгодно; почему я должен обойтись без некоторых переменных.
Давайте реализуем наши включения! Допустим, наш базовый шаблон имеет 5 переменных, и я включаю шаблон, который использует только одну из этих переменных, это обозначение, которое будет предпочтительнее.
1
|
{% включают "ProjectMyBundle:Sub:template.html.twig" только с {"object":myVar} %}
|
Таким образом, в моем шаблоне будет доступна только переменная «объект». Это ограничивает копирование бесполезных переменных и, следовательно, выделение памяти (экономия времени и потребления памяти).
Код и варианты использования
1
2
3
4
5
6
|
// Контроллер
// Здесь генерирует шаблон, передавая внушительную переменную (коллекцию), содержащую все объекты для данной таблицы
что такое варган? функция testAction() {
$объекты = $ Этой->контейнер->получить(«doctrine.orm.default_entity_manager») -> получить репозиторий («ProjectMyBundle: Тест»)->найтиВсе();
возвращение массив("предметы" => $объекты);
}
|
Мы перебираем нашу коллекцию и передаем шаблон каждой итерации коллекции в шаблон. В этом случае каждый раз, когда мы вызываем интеграцию шаблона, копируются все переменные, а также переданные с помощью вариант "с". В нашем первом случае мы могли бы очень хорошо представить доступ к нашей коллекции (объектам), а также к нашей текущей итерации (объекту).
1
2
3
4
5
|
{#Шаблон 1#}
{% для объект в объектах %}
{% включают "ProjectMyBundle:Sub:template.html.twig" с {"object": object} %}
{% конец %}
|
Во втором случае я активирую опцию только что позволяет копировать только переменные, переданные в качестве параметров. Легкий ?
1
2
3
4
5
|
{#Шаблон 2#}
{% для объект в объектах %}
{% включают "ProjectMyBundle:Sub:template.html.twig" только с {"object": object} %}
{% конец %}
|
эталонный тест
Я провел тесты с шаблонами и кодом, приведенным в части выше. Я выполнил 5 итераций каждого шаблона, не забывая очищать кеш перед каждым первым тестом.
На этом графике мы видим, что загрузка, как правило, дольше для тех, кто не использует эту опцию. только. Разница имеет тенденцию уменьшаться после кэширования. Это связано с тем, что мой шаблон небольшой и используется мало переменных. В более прикладных случаях выигрыш достигает 30%.
Здесь, если мы усредним значения, мы получим среднюю разницу в 9 мс (48,6 – 39,6 = 9). Таким образом, мы можем рассчитать приблизительный выигрыш в 20%, даже если это следует учитывать в нашем случае, поскольку первый выстрел ужасно длинный без использования « только .