Привет, Хабр!

Сергей Пантелеев, Кирилл Несмеянов и Данил Щуцкий собрали новости за декабрь в 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

Видео версия дайджеста: 

Комментарии (1)