Привет, Хабр!
Сергей Пантелеев, Кирилл Несмеянов и Данил Щуцкий собрали новости за декабрь в PHP, Symfony и Laravel (соответственно). Всё самое интересное. Если вы хотите быть в теме происходящего, этот материал точно для вас. ?
Новости PHP с Сергеем Пантелеевым
Вышли PHP 8.2.27, PHP 8.3.15 и PHP 8.4.2
Выпуски с исправлением ошибок вышли по расписанию. Кстати, в качестве эксперимента, релизы впервые созданы на GitHub, раньше создавались только теги. Команда релиз-менеджеров пробует найти способы дать понять людям, что создание тега – не означает релиз, это уже несколько раз аукалось, и теперь попробовали решить проблему малой кровью. Для тех, кто не в курсе, сборки архивов и создание тегов происходит по вторникам, а анонс выпуска – по четвергам. Два дня необходимы для подготовки сборок под Windows и тестирования сторонними командами. До публикации новости на сайте php.net и сообщения в списке рассылок, релиз не считается выпущенным и полагаться на тег не стоит.
⚠️Закончилась активная поддержка PHP 8.2
Начиная с этого года, версии PHP поддерживаются на протяжении четырех лет: 2 года активной поддержки и 2 года исправлений безопасности. Поддержка исправлений безопасности PHP 8.1 продлена до 31 декабря 2025, а PHP 8.2 будет обслуживаться до 31 декабря 2026 года. PHP 8.2.27 стал последним выпуском в цикле активной поддержки и сборку финального релиза я решил записать на видео, посмотрите, если интересно.
«Своя игра» по PHP. Финал
Состоялась финальная игра этого года, в которой сошлись Кирилл Несмеянов, Алексей Гагарин и Павел Бучнев. В 2025 году мы добавим еще больше интерактива, обязательно пишите в комментариях, каких гостей вы хотели бы увидеть на нашем канале, а может быть вы и сами не против принять участие в одной из игр? – Делитесь своими мыслями, мы читаем и прислушиваемся к каждому комментарию.
PHP Russia 2024
В начале декабря в Москве прошла пятая конференция PHP Russia. Многие уже написали свои впечатления от поездки, загляните в телеграм-каналы Данила или Сергея Предводителева. Валентин Удальцов взял интервью у единственного англоязычного спикера Иоанниса Лукериса, посмотрите, если пропустили.
Мы, командой CutCode, также взяли интервью у спикеров и гостей, посмотрите наш отчет о поездке на канале CutCode и загляните в телеграм-канал Fart Time, чтобы посмотреть на конференцию немного с другой стороны!
От себя добавлю, что рад был увидеть многих, с кем раньше пересекались только на стримах и на GitHub, надеюсь, мы увидимся и в следующем году :)
Вышел Rector 2.0
Основная цель этого релиза – улучшение производительности за счет обновления зависимостей:
php-parser 4.x до 5.0
PHPStan 1.x до 2.0
минимальная версия PHP 7.4
Команда не оставила пользователей и без новых функций: добавлен флаг --only
для обработки только одного правила, добавлены аннотации Behat и добавлена возможность использовать значение аннотации в качестве аргумента атрибута.
Вышла Laravel Nova 5
В пятой версии админки от команды Laravel модернизировали зависимости (Inertia 2, PHP 8.1+, Laravel 10+), добавлены панели вкладок и представлена улучшенная обработка полей.
Еще чуть-чуть и Nova догонит MoonShine, у которой кстати, на днях так же вышла мажорная третья версия. Посмотрите трансляцию релиза, если пропустили.
PHP Core
Большинство новостей ядра PHP подробно освещаются в серии PHP Core Roundup от PHP Foundation, мы лишь быстро по ним пробежимся:
? RFC: Attributes on Constants
Атрибуты были впервые представлены в RFC: Attributes v2. Daniel Scherzer предлагает добавить поддержку атрибутов для констант вне классов во время компиляции.
Подразумеваются константы, определенные с помощью ключевого слова const
, а не с помощью функции define
. Голосование за RFC продлится до 6 января, скорее всего, RFC будет принят.
// Так можно
#[\MyAttribute]
const Example1 = 1;
// А так нельзя
#[\MyAttribute]
const Example2 = 2,
Example3 = 3;
? RFC: Error Backtraces v2
Сейчас ошибки PHP не предоставляют обратных трассировок, что может затруднить выяснение их причины. Eric Norris предлагает добавить новую константу, E_FATAL_ERRORS
, которая включает обратные трассировки для фатальных ошибок. Голосование за RFC продлится до 10 января.
?RFC: Asymmetric Visibility for Static Properties
В RFC Asymmetric Visibility v2 для PHP 8.4 была намеренно опущена поддержка асимметричной видимости для статических свойств. Это было связано в первую очередь с ожидаемой сложностью реализации и относительно небольшим количеством случаев использования. Однако, уже сработавшаяся команда Ilija Tovilo и Larry Garfield провели исследование, что реализовать это проще, чем предполагалось, поэтому предлагают добавить асимметричную видимость статических свойств, для полноты картины.
class Example
{
public private(set) static string $classTitle = 'Example class';
// Implicitly public-read, just like object properties.
protected(set) static int $counter = 0;
public static function changeName(string $name): void
{
// From private scope, so this is allowed.
self::$classTitle = $name;
}
}
print Example::$classTitle; // Так можно.
Example::$classTitle = 'Nope'; // А так нельзя.
Большой ежегодный опрос по PHP!
Все ещё есть возможность поучаствовать в ежегодном опросе по PHP, чтобы понять, на чем мы пишем, чем живем и куда движемся! В этом году силами CutCode пытаемся собрать самые актуальные данные и вместе взглянуть на развитие PHP в 2024 году. В прошлом году 1120 разработчиков рассказали, на каких версиях PHP сидят, какие фреймворки любят и как относятся к ИИ. В этом году мы постарались сделать опросеще интереснее! Вопросы про развитие, новые технологии и даже пару неожиданных тем. Опрос анонимный. Но кто оставит свой email могут поучаствовать в розыгрыше слона. А шанс повлиять на сообщество есть у каждого! Пройдите опрос и помогите собрать срез по русскоязычной PHP-тусовке! По итогам сделаем подборки статей, докладов, каналов по PHP. Все результаты опубликуем на phpcommunity.ru и в статье на «Хабре».
PHP-слоны
Если вы не успели купить PHP-слона со скидкой в прошлом году, то не переживайте, все промокоды в 2025 году продолжат работать. Впереди еще много праздников, и PHP-слоник будет отличным подарком себе или другу. Переходите на сайт elephpants.ru и вводите промокод CutCode
, чтобы получить слоника со скидкой.
Laravel дайджест с Данилом Щуцким
11.34 Add Number::spellOrdinal() to spell ordinals as words.
https://github.com/laravel/framework/pull/53661
Joel Stein добавил метод spellOrdinal()
в хелпер Number
, чтобы записывать порядковые числительные словами.
'The ' . Number::spellOrdinal(40) . ' president of the United States is Ronald Reagan';
Передаем integer, получаем число прописью.
11.34 Add shorthands for fake HTTP responses
https://github.com/laravel/framework/pull/53663
Jason McCreary добавил сокращённые записи для имитации HTTP-ответов - упрощает взаимодействие через метод fake
. До версии 11.34 можно было использовать сокращённые массивы, но этот PR добавляет возможность задавать строку в качестве тела ответа или целое число для статус-кода.
// До
Http::fake([
'google.com' => Http::response('Hello World'),
'github.com' => Http::response(['foo' => 'bar']),
'forge.laravel.com' => Http::response(status: 204),
]);
// После
Http::fake([
'google.com' => 'Hello World',
'github.com' => ['foo' => 'bar'],
'forge.laravel.com' => 204,
]);
11.34 Add Request::fluent method
https://github.com/laravel/framework/pull/53662
Стив Бауман добавил метод fluent()
в класс HTTP Request, который позволяет удобно передавать входные данные в цепочке вызовов.
/** @var Illuminate\Http\Request $request */
$data = $request->fluent();
$data->title;
$data->body;
// etc.
11.35 URI
https://github.com/laravel/framework/pull/53731
Автор этого PR сам Taylor. Представил Uri — класс, основанный на библиотеке URI от PHP League. Uri упрощает работу с URI в вашем Laravel-приложении и предоставляет дополнительные удобства для работы с именованными маршрутами.
Ключевая особенность класса Uri — это создание и манипуляция строками URI, включая работу с параметрами запроса, фрагментами и путями. теперь мы можем с помощью этого support класса строить URL, Path, Fragment и при этом получать scheme()
, host()
и так далее:
use Illuminate\Support\Uri;
$uri = Uri::of('https://moonshine-laravel.com')
->withPath('links')
->withQuery(['page' => 2])
->withFragment('new');
(string) $url; // https://moonshine-laravel.com/links?page=2#new
$uri->path(); // links
$uri->scheme(); // https
$uri->port(); // null
$uri->host(); // moonshine-laravel.com
11.35 Allow sorting routes by precedence in artisan routes:list.
https://github.com/laravel/framework/pull/53706
PR затрагивает консольную команду с отображением списка роутов. По умолчанию маршруты сортируются по URI. Однако не всегда легко определить, какие маршруты будут иметь приоритет над другими (особенно если маршруты добавляются из пакета).
И при переопределении роутов могут возникнуть конфликты, а понять где именно - сложно. Этот pull request добавляет опцию --sort=precedence
. В итоге мы получим список роутов, которые будут отсортированы не по URI, а на основе того как они объявлены. Тем самым, проблему неправильного переопределения будет проще вычислить.
11.36 Uri and UriQueryString implement Stringable
https://github.com/laravel/framework/pull/53873
Теперь будет множество манипуляций с новым support классом URI от Taylor. Этот PR добавил реализацию интерфейса Stringable
, странно что Taylor сразу не добавил, но в общем теперь имплементация присутствует.
11.36 Add new Uri class to default, global aliases
https://github.com/laravel/framework/pull/53884
Этот PR также касается URI - добавлен глобальный alias под него, чтобы можно было использовать в блейдах и где угодно без импорта.
Symfony дайджест с Кириллом Несмеяновым
Привет, симфоняшки!
Это снова я, Кирилл Несмеянов. Продолжаю вас знакомить с всякими мелкими новиночками ушедшего месяца. Заканчиваем с Symfony 7.2. Не забывайте вступать в symfony-чат.
Задержка при повторной отправке сообщения в messenger
При использовании компонента Messenger можно выбросить RecoverableMessageHandlingException
чтобы принудительно повторить отправку сообщения. В Symfony 7.2 можно передать задержку повтора в конструктор этого исключения. Это полезно, например, при повторной отправке HTTP-запроса, включающего Retry-After заголовок ответа. Да и вообще, кажется, довольно очевидно, если мессенджер взаимодействует с I/O, то не долбиться каждый раз во внешние системы, а делать это с некой задержкой. В следующем релизе ждём Circuit Breaker из коробки, получается.
Источник: symfony.com
Улучшения в Coalesce-выражениях
Компонент ExpressionLanguage
поддерживает оператор "объединения с нулем", т.е. этот самый "coalescence":
( `foo ?? 'no'`, `foo.baz ?? foo['baz'] ?? 'no'`, и т. д.).
Однако, в отличие от эквивалентного оператора PHP, он выбрасывает исключение при попытке доступа к несуществующей переменной. Ребята поправили это поведение в Symfony 7.2, и оператор объединения с нулем теперь ведет себя точно так же, как оператор PHP.
Источник: symfony.com
Передача атрибутов в Passport через логин пользователя
При использовании метода "login()" для программного (императивного) входа пользователей можно передавать различные параметры:
public function someAction(Security $security): Response
{
// Например, логин через пользовательский файрвол "other_firewall"
$security->login($user, 'form_login', 'other_firewall');
}
В Symfony 7.2 теперь можно определить пользовательские атрибуты для передачи в Passport:
$security->login($user, attributes: ['referer' => 'https://oauth.example.com']);
Источник: symfony.com
Добавлена опция "calendar" в "DateType"
PHP класс IntlCalendar
позволяет выбрать любой из календарей, определенных в библиотеке ICU, а также определить пользовательские настройки календаря. В Symfony 7.2 было улучшено поле формы DateType
, чтобы разрешить передачу пользовательского календаря через новую опцию "calendar".
Простыми словами, теперь в DateType
тип можно передать ссылку на объект IntlCalendar
.
Источник: symfony.com
Принудительное включение поддержки цветов в консоли
В Symfony 4.4 была добавлена поддержка переменной окружения "NO_COLOR"
как способ отключить подсветку вывода в консоли. В Symfony 7.2 добавлена поддержка противоположной переменной окружения, называемой "FORCE_COLOR"
.
Достаточно установить для этой переменной окружения любое значение, и такие компоненты, как "Console"
, "PhpUnitBridge"
, "VarDumper"
и проч., будут выводить содержимое с поддержкой цветов.
Источник: symfony.com
Поддержка виртуальных свойств в VarDumper
Одна из основных "фич" в PHP 8.4 является поддержка "свойств классов" (или "хуков") помимо "полей классов", как это было ранее. Свойства, напоминаю, это переменные/поля класса, которые позволяют определить дополнительную логику при получении и установке значений. Виртуальными свойствами в рамках PHP принято называть свойства, которые реализуют исключительно логику без хранения в них значения.
class VirtualHookedClass
{
// ...
public string $fullName {
get => $this->firstName . ' ' . $this->lastName;
}
private $untypedFullName {
get => $this->firstName . ' ' . $this->lastName;
}
}
В Symfony 7.2 добавили поддержку свойств (хуков) в компоненте VarDumper для дампа содержимого объекта. И хотя значение хука не будет показано (чтобы избежать запуска логики внутри него), вы увидите их имена и типы:
Признаться, я не проверял поведение для "не виртуальных" свойств, однако, подозреваю что они тоже поддерживаются, просто выводят хранимое значение как и обычные поля. Поэтому акцент в этом анонсе был исключительно на виртуальных свойствах.
Источник: symfony.com
Доступ к расчетной надежности пароля
Проверка валидатора PasswordStrength
проверяет, что данный пароль достиг минимальной "надёжности", настроенной в этой проверке. В Symfony 7.2 изменили видимость "estimateStrength()"
метода валидатора с private на public. Это позволяет получить доступ к предполагаемой надежности пароля и отобразить ее, например, в интерфейсе, чтобы пользователи могли лучше оценить надёжность своих паролей.
Источник: symfony.com
Упрощение юнит-тестирования RequestStack
Раньше при использовании RequestStack
в юнит-тестах для настройки запросов требовалась микропортяночка кода из 3х строк. И хотя она не такая уж и страшная, но это постоянное дублирование кода.
$requestStack = new RequestStack();
$requestStack->push(Request::create('/'));
$someCustomClass = new MyCustomClass($requestStack);
В Symfony 7.2 упростили инстанциирование RequestStack, добавив конструктор, который принимает массив запросов в качестве начального значения. Так что микропортянка сократилась, фактически, до 1 строчки.
$someCustomClass = new MyCustomClass(
new RequestStack([ Request::create('/') ]),
);
Источник: symfony.com
Действие по умолчанию в HTML Sanitizer
В Symfony 7.2 добавлен новый "defaultAction()"
метод в компонент HtmlSanitizer
. Этот метод устанавливает действие по умолчанию для элементов, которые явно не разрешены или не заблокированы:
use Symfony\Component\HtmlSanitizer\HtmlSanitizer;
use Symfony\Component\HtmlSanitizer\HtmlSanitizerAction;
$config = (new HtmlSanitizerConfig())
->defaultAction(HtmlSanitizerAction::Block)
->allowElement('p');
$sanitizer = new HtmlSanitizer($config);
HtmlSanitizerAction — это PHP enum с тремя вариантами:
Drop - удаляет элемент и его дочерние элементы;
Block - удаляет элемент, но сохраняет его дочерние элементы;
Allow - сохраняет элемент.
Источник: symfony.com
Поддержка использования "defaultNull()" в BooleanNode
Кто не понял, то новость касается бандлов. А точнее их конфигурации. Текущее поведение "defaultNull()"
в BooleanNode
приводит значения null к true. Т.е. если конфиг не указан явно, то считалось, что выставлено значение по умолчанию, т.е. null, что эквивалентно выставлению true. Подозреваю, такая логика была.
В Symfony 7.2 обновили этот метод, чтобы можно было более грамотно и явно определять булевы значения, допускающие значение null. Таким образом, добавление этой опции меняет тип с bool на boollnull.
->booleanNode('enabled')
->defaultNull()
->end()
Источник: symfony.com
Улучшения анонимности IP-адреса
Класс IpUtils
содержит метод "anonymize()"
для сокрытия части IP-адреса для конфиденциальности пользователя. В Symfony 7.2 добавили два новых аргумента к этому методу, чтобы можно было указать, сколько байт нужно анонимизировать:
$ipv4 = IpUtils::anonymize('123.234.235.236', 2);
// '123.234.0.0'
$ipv6 = IpUtils::anonymize('2a01:198:603:10:396e:4789:8e99:890f', 3, 10);
// '2a01:198:603::'
Источник: symfony.com
Добавлен StringNode
При определении конфигурации можно использовать множество типов узлов для значений конфигурации (логические, целые, числа с плавающей точкой, перечисления, массивы и т.д.). Однако нельзя было напрямую указать строковые значения. Их следовало указывать как scalar узлы (т.е. ScalarNode
).
В Symfony 7.2 добавили строковый тип узла и "stringNode()"
метод соответственно, позволяющие явно определять значения конфигурации как строки:
$rootNode
->children()
// ...
->stringNode('username')
->defaultValue('root')
->end()
->stringNode('password')
->defaultValue('root')
->end()
->end()
;
Источник: symfony.com
Улучшения Security профилировщика
В Symfony 7.2 панель безопасности Symfony Profiler была дополнена несколькими новыми функциями. Во-первых, была обновлена вкладка аутентификаторов. Ранее аутентификаторы, которые не поддерживали запрос, не отображались:
Теперь, для упрощения отладки видны все аутентификаторы приложения. Если аутентификатор не поддерживает запрос, он будет помечен как «не поддерживается»:
Помимо этого, при использовании файрволла с отслеживанием состояния вкладка токенов деаутентифицированных пользователей теперь включает ссылку на запрос, содержащий ранее аутентифицированного пользователя (например ссылку на логаут роут):
Вкладка аутентификаторов также была переработана для более четкого отображения информации.
Теперь она показывает, является ли аутентификатор ленивым, и включает любые исключения, переданные методу "onAuthenticationFailure()"
:
Источник: symfony.com
Twig
Всё просто, вышел Twig 3.15. Это отдельный пакет, который никак (ну почти) не связан с Symfony, но из-за его популярности и глубокой интеграции в экосистему симфони - было бы нерациональным обойти новинки Twig стороной.
Twig: Поддержка комментариев внутри выражений
В Twig однострочные или многострочные комментарии определяются с помощью `{# ... #}` синтаксиса. Однако вы не можете добавлять комментарии с использованием этого синтаксиса внутри блоков или переменных.
Twig 3.15 поддерживает новый тип комментариев, которые используют синтаксис `# ...` и могут быть добавлены практически в любом месте:
{{
# Внутри выражений!
"Hello World" | trans
}}
{{
{
# Внутри object-переменной
hello: 'world', # или даже тут
} | join(', ') # а можно тут
}}
{% props
# да где угодно...
some = true,
any = null,
%}
Источник: symfony.com
Twig: Функция enum
Twig 3.15 добавляет функцию, enum()
которая поможет вам работать с перечислениями (енамами) в шаблонах:
{# вывод значения элемента перечисления (кейса у енама) #}
{{ enum('Path\\To\\EnumClass').SomeCase.value }}
{# вызов статического метода у перечисления #}
{{ enum('Path\\To\\EnumClass').method() }}
{# вывод всех значений перечисления #}
{% for case in enum('Path\\To\\EnumClass').cases() %}
<li>{{ case.value }}</li>
{% endif %}
Источник: symfony.com
Twig: Поддержка логического "xor"
Twig 3.15 добавляет поддержку оператора xor
, который вычисляется в true когда только один из его операндов равен true, но не оба.
{% if coupon.isValid xor user.hasLoyaltyDiscount %}
<p>Ого! Ничего себе у вас тут скидочка!</p>
{% else %}
<p>Неа, выберите или скидочный купон, или скидку за лояльность. Оба варианта нельзя</p>
{% endif %}
Источник: symfony.com
Twig: Исправления приоритета операторов
Операторы Twig соответствуют поведению эквивалентных операторов PHP, за исключением некоторых различий в приоритете операторов. Эти различия были введены PHP 7.4 при изменении приоритета конкатенации. В Twig 3.15 больше не рекомендуется использовать некоторые операторы без скобок, т.е. они помечены как устаревшие, чтобы помочь исправить выражения перед обновлением до Twig 4, где приоритет операторов изменится:
{# ❌ это выражение устарело #}
{{ foo ?? bar ~ baz }}
{# ✅ лучше написать так (поведение Twig 3.x) #}
{{ (foo ?? bar) ~ baz }}
{# ✅ или так (поведение Twig 4.x ) #}
{{ foo ?? (bar ~ baz) }}
{# ❌ это выражение устарело #}
{{ foo ~ bar + baz }}
{# ✅ лучше написать так (поведение Twig 3.x) #}
{{ (foo ~ bar) + baz }}
{# ✅ или так (поведение Twig 4.x) #}
{{ foo ~ (bar + baz) }}
{# ❌ это выражение устарело #}
{{ not foo * bar }}
{# ✅ лучше написать так (поведение Twig 3.x) #}
{{ not (foo * bar) }}
{# ✅ или так (поведение Twig 4.x) #}
{{ (not foo) * bar }}
Источник: symfony.com
Twig: Стратегия автоматического экранирования для JSON файлов
Twig применяет различные стратегии экранирования автоматически в зависимости от расширения файла. Например, файлы с именем template_name.js.twig
применяют js-стратегию экранирования по умолчанию.
Начиная с Twig 3.15, js-стратегия экранирования также применяется к файлам JSON (например, template_name.json.twig
). Ранее они использовали html-стратегию, что потенциально могло вызвать проблемы безопасности.
Источник: symfony.com
Twig: Депрекейт sandbox-тега
Функция Twig sandbox
позволяет безопасно оценивать ненадежный код. В предыдущих версиях это делалось с помощью sandbox-тега. Начиная с Twig 3.15 этот тег устарел. Вместо этого предлагается использовать sandboxed-атрибут функции include()
:
{# ❌ так больше не рекомендуется #}
{% sandbox %}
{{ include('untrusted_template.html') }}
{% endsandbox %}
{# ✅ лучше так #}
{{ include('untrusted_template.html', sandboxed: true) }}
Источник: symfony.com
Twig: Улучшения депрекейтов для функций
Twig позволяет отмечать фильтры и функции как устаревшие с помощью deprecated
опции:
new TwigFilter('...', ..., ['deprecated' => true, 'alternative' => 'new_one']);
Начиная с Twig 3.15, необходимо использовать новую опцию deprecation_info
, которая предоставляет более подробную информацию об устаревании и его альтернативах:
use Twig\DeprecatedCallableInfo;
new TwigFilter('...', ..., ['deprecation_info' => new DeprecatedCallableInfo(
'vendor/package', # Устаревший пакет
'3.14', # Устаревшая версия
'new_one', # Альтернативный фильтр (опционально)
'other-vendor/some-package', # Пакет альтернативного фильтра (опционально)
'4.2.0' # Версия альтернативного пакета (опционально)
)])
Источник: symfony.com
Twig: Проверка функторов Twig во время компиляции
Шаблоны Twig не поддерживают использование try ... catch
для проверки наличия фильтра, функции или тега перед их вызовом. Это ограничение может привести к ошибкам в сторонних пакетах, которые зависят от дополнительных функторов Symfony. Twig 3.15 представляет новый guard
-тег, который проверяет вызываемые объекты Twig во время компиляции и пропускает работу, если вызываемый функтор не существует.
Допустим у нас есть пакет, который поддерживает как Webpack Encore
, так и AssetMapper
, и пытается использовать следующий шаблон:
{% if app_uses_webpack_encore %}
{{ encore_entry_link_tags('some-asset') }}
{% else %}
{{ importmap('some-asset') }}
{% endif %}
Этот шаблон будет работать только если в приложении установлены и Webpack Encore
и AssetMapper
. Если отсутствует encore_entry_link_tags()
или importmap()
, то Twig упадёт с ошибкой.
С новым guard
-тегом в Twig 3.15 можно избежать таких ошибок, полностью пропуская недоступные функторы. Предыдущий пример теперь можно записать так:
{% guard function encore_entry_link_tags %}
{{ encore_entry_link_tags('some-asset') }}
{% endguard %}
{% guard function importmap %}
{{ importmap('some-asset') }}
{% endguard %}
Источник: symfony.com
Twig: Улучшения dot-оператора
Функция attribute()
позволяет получить доступ к полям или свойствам переменных или объектов, где имя атрибута/свойства является динамическим.
{# Использование dot-нотации, т.к. свойство fullName - литерал #}
{{ user.fullName }}
{# Требуется использование функции attribute(), т.к. имя свойства находится внутри переменной #}
{% for property in ['fullName', 'email', 'phoneNumber'] %}
{{ attribute(user, property) }} <br>
{% endfor %}
В Twig 3.15 функция attribute()
устарела, а оператор точки был расширен для обработки динамических свойств:
{# Свойство, выводимое из переменной должно быть в скобках #}
{% for property in ['fullName', 'email', 'phoneNumber'] %}
{{ user.(property) }} <br>
{% endfor %}
Несмотря на то, что функция attribute()
помечена устаревшей, она останется доступной и в Twig 4.0, чтобы обеспечить более плавный процесс обновления.
Еще одним усовершенствованием dot-оператора является возможность доступа к константам класса непосредственно из объекта:
{# Ранее, так же как и в PHP, требовалось использовать функцию constant #}
{{ constant('App\\Some\\Namespace\\Of\\Some\\Class::CONSTANT_NAME') }}
{# теперь к константам можно обращаться так же как к свойствам #}
{# SHIPPING_TYPE_EXPEDITED - это имя константы в инстансе от Order класса #}
{{ order.SHIPPING_TYPE_EXPEDITED }}
Источник: symfony.com
Twig: Улучшения именованных аргументов
Макросы Twig похожи на функции в языках программирования и полезны для повторного использования фрагментов. Начиная с Twig 3.15 можно использовать именованные аргументы при вызове макроса с синтаксисом argument: value
, как в PHP:
{{ forms.field(type: 'text', name: 'user[name]') }}
Именованные аргументы также поддерживаются при передаче аргументов с помощью dot-оператора:
{{ user.fullName(maxLength: 32) }}
{% for property in ['fullName', 'email', 'phoneNumber'] %}
{{ user.(property)(escape: true, maxLength: 32) }} <br />
{% endfor %}
Благодаря этим изменениям именованные аргументы теперь поддерживаются везде: в функциях, фильтрах, тестах, макросах и аргументах dot-операторов.
Источник: symfony.com
Имена вызываемых аргументов PHP в свободной форме
Ранее Twig требовал имена аргументов в snake_case
при вызове функторов, независимо от их исходной сигнатуры. В Twig 3.15 можно использовать либо snake_case
, либо camelCase
, независимо от того, какой формат используется сигнатурой PHP:
{# Оба синтаксиса вернут идентичный результат #}
{{ order.summary(include_total: true) }}
{{ order.summary(includeTotal: true) }}
Вообще, вся эта Laravel-like магия не очень прикольна. Слава Уицилопотчли, что она остаётся только в шаблонизаторе. Например, что будет, если в методе будет два аргумента, один в camelCase
, другой в snake_case
. Понимаю, что кейс вряд ли возможен, но как решить проблему конфликтов имён остаётся загадкой.
Источник: symfony.com
Twig: Распаковка аргументов
Оператор `...`
(распаковки, spread, variadic, проч.) теперь может использоваться при вызове функции:
{% set attr = [{type: 'submit'}, {class: 'btn btn-primary'}, {'data-tracking-id', '12345'}] %}
{{ html_attributes(...attr) }}
Источник: symfony.com
Twig: Расширенная поддержка стрелочных функций
Стрелочные функции, любимые многими разработчиками, ранее поддерживаемые в фильтрах и функциях, теперь поддерживаются везде. Теперь их можно использовать в тестах, аргументах макросов и аргументах методов:
{% set people = [
{first: "Данил", last: "Иванович"},
{first: "Данислав", last: "Иваныч"},
{first: "Деянир", last: "Ван-клодыч"},
] %}
{# передача стрелочной функции в макрос #}
{{ _self.display_people_names(people, (person) => person.first) }}
А ещё их можно устанавливать в переменные:
{# определение стрелочной функции и сохранение ее в переменной #}
{% set first_name_fn = (p) => p.first %}
{{ _self.display_people_names(people, first_name_fn) }}
Источник: symfony.com
Видео версия дайджеста: