PHP и Laravel дайджест новостей за октябрь 2024 года

от автора

Всем привет!

Это дайджест новостей от CutCode. Давайте посмотрим, что произошло за прошедший месяц в мире PHP и Laravel.

Давайте посмотрим, что произошло за прошедший месяц в мире PHP.

Новости PHP

PHP 8.4.0 RC3 доступен для тестирования

Перед финальным выпуском, который ожидается 21 ноября, остался последний релиз-кандидат.

В день выхода PHP 8.4, 21 ноября, на канале CutCode мы с видными представителями PHP-сообщества обсудим главные фишки релиза, поговорим о PHP в целом и разыграем со зрителями PHP-слоника.

Вышли PHP 8.2.25 и PHP 8.3.13

Выпуски с исправлением ошибок вышли по расписанию.

Open Source Цех #1

Все, наверное, уже в курсе, что благодаря Валентину Удальцову, начиная с PHP 8.4, мы сможем вызывать метод инициируемого объекта с помощью ключевого слова new без скобок.

Валентин не остановился на реализации своего RFC и решил упростить нам работу, добавив новое правило в PHP CS Fixer, да еще и в прямом эфире.

Посмотрите запись трансляции, если пропустили.

Открыта программа раннего доступа PhpStorm 2024.3

В будущей версии PhpStorm появится поддержка вызова методов инициируемого объекта с помощью ключевого слова new без скобок, определение и преобразование циклов foreach в новые функции для работы с массивами: array_find(), array_find_key(), array_any() и array_all(), поддержка хуков свойств и многое другое.

PHP Russia 2024

2 и 3 декабря в Москве пройдёт конференция Highload, в рамках которой 16 докладов будут выделены под PHP Russia.

Список докладов уже опубликован на сайте конференции.

Пыхап № 1

8 ноября в Москве Валентин Удальцов собирает первый в истории митап от канала Пых, на котором выступят Андрей Клименко, Вадим Занфир и Сергей Жук.

Вход бесплатный, но по билетам, кто не сможет присоединиться, подключайтесь к трансляции.

Symfony исполнилось 19 лет 🎂

Спасибо сообществу за почти два десятилетия инноваций и вклада в открытый код. Пусть впереди команду Symfony ждет еще много лет развития!

«Своя игра» по PHP #3

30 октября пройдёт третий выпуск викторины «Своя игра» по PHP от CutCode. В этот раз на интеллектуальной арене встретятся Александр Черняев, Павел Бучнев и Сергей Предводителев.

Как обычно, пишите в комментариях свои предложения и замечания, а также кого вы хотели бы видеть на следующих играх. А, может, вы хотели бы посмотреть на суперфинал среди победителей прошедших игр? – напишите в комментариях.

Большинство новостей ядра PHP подробно освещаются в серии PHP Core Roundup от PHP Foundation, мы лишь быстро по ним пробежимся:

✅ RFC: Change Directory class to behave like an opaque object

RFC, о котором мы говорили в прошлый раз принят единогласно. Класс Directory, вероятно, является первым экземпляром того, что мы сейчас называем «непрозрачным объектом». Непрозрачные объекты обычно являются результатом преобразования ресурсов в объекты, что в общем случае подразумевает, что они являются окончательными, не сериализуемыми, не инициализируемыми с помощью ключевого слова new, не могут быть приведены и не реализуют никаких методов. Однако, поскольку этот класс существует со времен PHP 4, ничего из этого формально не реализовано.

Начиная с PHP 8.5 класс Directory:

  • Будет окончательным.

  • Будет выбрасывать ошибку при инициализации с помощью ключевого слова new.

  • Будет предотвращено клонирование экземпляров класса Directory.

  • Будет запрещена сериализация с помощью doc-комментария @not-serializable к заглушке класса.

  • Будет запрещено создание динамических свойств для экземпляра класса Directory с помощью doc-комментария @strict-properties к заглушке класса.

📣 RFC: Add get_declared_enums() function

Сейчас нет способа получить только объявленные перечисления, Juliette Reinders Folmer и Ayesh Karunaratne предлагают добавить новую функцию get_declared_enums().

Перечисления также обнаруживаются с помощью функций class_exists() и get_declared_classes(), что также предлагается исправить в этом RFC.

📊 RFC: Add persistent curl share handles

Сейчас модуль cURL не поддерживает постоянные дескрипторы совместного доступа cURL. Соединения передаются только между дескрипторами в рамках одного SAPI-запроса.

Eric Norris предлагает добавить новую функцию, curl_share_init_persistent(), которая сначала проверит глобальную память воркера SAPI на наличие существующего дескриптора совместного доступа, если таковой будет найден, то функция сразу же его вернет, в противном случае функция создаст новый, применит указанные опции ресурса, сохранит его в глобальной памяти и вернет его.

📣 RFC: Change behaviour of array sort functions to return a copy of the sorted array

Сейчас в функции сортировки массивов, массив для сортировки передается по ссылке. Однако, начиная с PHP 5.6, эти функции всегда возвращали только значение true.

Gina Peter Banyard предлагает изменить возвращаемое значение функций sort(), rsort(), asort(), arsort(), ksort(), krsort(), natsort(), natcasesort(), usort(), uasort(), uksort(), array_multisort(), shuffle(), array_walk(), array_walk_recursive() и вместо true возвращать копию преобразованного массива.

Laravel дайджест

Обновления Laravel

11.26 Allows Unit & Backed Enums for registering named RateLimiter & RateLimited middleware

https://github.com/laravel/framework/pull/52935

В прошлом дайджесте мы с вами видели интеграцию Enum всюду, теперь также затронут и RateLimit, и вместо строкового наименования RateLimit можно просто передавать Enum, и это также будет работать. 

11.26 Add make:job-middleware artisan command

https://github.com/laravel/framework/pull/52965

Двигаемся дальше к следующему pull request: добавлена новая artisan-команда, которая создает middleware для job. В целом, те же самые middleware, только для job, и они у нас складируются в директорию app/Jobs/Middleware

<?php namespace {{ namespace }}; use Closure; class {{ class }} {     /**      * Process the queued job.      *      * @param  \Closure(object): void  $next      */     public function handle(object $job, Closure $next): void     {         $next($job);     } }

Если мы посмотрим на изменения в stub для job, то не увидим ничего принципиально нового. Единственное отличие — наличие типизации прямо в stub, причём даже в doc-блоке, что довольно необычно. Несмотря на это, Тейлор всё равно принял и смержил такой пулл-реквест.

11.26 Feat: factory generic in make:model command

https://github.com/laravel/framework/pull/52855

Следующий пулл-реквест снова касается стабов: в них добавили дженерики как для моделей, так и для их фабрик (в тех случаях, где фабрики присутствуют).

<?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; class Comment extends Model {     /** @use HasFactory<\Database\Factories\CommentFactory> */     use HasFactory; }

11.26 Allow mass assignment with mutators when using model::guarded

https://github.com/laravel/framework/pull/52962

Следующий pull request касается Eloquent модели: массовая гидрация модели, fillable, guarded. Если мы работаем с полями, которые соответствуют полям в таблице, то все работало нормально, но если мы взаимодействуем с мутаторами, у которых наименование не соответствует полям в таблице, то здесь уже проверки при наполнении не будут срабатывать. Этот pull request исправляет указанное поведение, и теперь с мутаторами также не будет проблем.

``` <?php namespace App\Models; use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Model; class User extends Model {      protected $guarded = []; // works      protected $fillable = ['address']; // works      protected $guarded  = ['some_unrelated_column']; // doesn't work     /**      * Interact with the user's address.      */     protected function address(): Attribute     {         return Attribute::make(             get: fn (mixed $value, array $attributes) => new Address(                 $attributes['address_line_one'],                 $attributes['address_line_two'],             ),             set: fn (Address $value) => [                 'address_line_one' => $value->lineOne,                 'address_line_two' => $value->lineTwo,             ],         );     } }  $user = new User; $user->fill(['address' => new Address(...)]); ```

11.26 Add stop() method to Process and Pool

https://github.com/laravel/framework/pull/52959

PR затрагивает класс Process для взаимодействия с процессорами через CLI. У нас был старт процессов, но при этом не было метода по остановке процессов. 

$this->pool = Process::pool(function (Pool $pool) {     $pool->path(base_path())->command('sleep 5');     $pool->path(base_path())->command('sleep 10'); })->start(); $this->pool->stop()

С этим pull request такой метод появился, он появился и в рамках процесса pool, и просто одиночного процесса. И помимо этого, также в метод stop добавили возможность передавать сигнал:

   /**      * Stop the process if it is still running.      *      * @param float $timeout      * @param int|null $signal      *      * @return int|null      */     public function stop(float $timeout = 10, ?int $signal = null)     {         return $this->process->stop($timeout, $signal);     }

11.27 feat: introduce option to change default Number currency

https://github.com/laravel/framework/pull/53022

В этом pull request нас ждет класс Number, где появился статический метод currency. Такие pull request появляются довольно часто — когда через статический метод в определенных, так называемых, классах-утилитах в Laravel добавляются методы, меняющие дефолтное поведение. Как и здесь, через статический метод указываем дефолтную валюту.

   /**      * The current default currency.      *      * @var string      */     protected static $currency = 'USD';

11.27 feat: add Str::doesntContain() method and supporting tests

https://github.com/laravel/framework/pull/53035

Снова helper по работе со строками Str. Был метод Str::contain(), а с этим pull request добавили  Str::doesntContain(). Но я думаю, объяснять, что он из себя представляет, не имеет никакого смысла.

11.27 Str: Add extension support for Str::inlineMarkdown()

https://github.com/laravel/framework/pull/53033

Двигаемся к следующему pull request. Снова класс по работе со строками. Еще недавно у нас появилась возможность добавлять extension для markdown. Были методы Str::inlineMarkdown() и str()->inlineMarkdown(), где extension не поддерживались, и соответственно, этим pull request добавлена такая поддержка. Фича, которая появилась давно, но ее забыли добавить в соседние методы, и постепенно с новыми релизами такие моменты закрываются.

11.27 Utilise Illuminate\Support\php_binary()

https://github.com/laravel/framework/pull/53008

Следующий pull request. Когда-то была добавлена функция для поиска PHP-бинарника. Соответственно, в команде по установке API еще использовался класс от Symfony, и соответственно, в данном PR поменяли на функцию из Laravel.

11.27 feat: narrow types for throw_if and throw_unless

https://github.com/laravel/framework/pull/53005

Для большинства, я думаю, не важный PR, но для меня лично интересный, так как функцию throw_if проапгрейдили в рамках док-блока. До этого статический анализ в том же самом PHP ругался о том, что если мы используем эту функцию, то все, что у нас двигается дальше, это уже unreachable statement из-за неправильного док-блока. Теперь этот момент исправлен. 

11.27 Improve Schema::hasTable() performance

https://github.com/laravel/framework/pull/53006

Следующий pull request затрагивает schema и метод hasTable. В данном случае улучшена производительность, оптимизированы запросы (стали более легковесными), и благодаря этому метод работет быстрее. Отличный pull request.

11.27 Add methods to the HTTP kernel to append middleware relative to other middleware

https://github.com/laravel/framework/pull/52897

PR затрагивает middleware — добавлены новые методы. Раньше через Kernek могли добавлять с вами middleware, но не могли добавлять в рамках приоритета. Теперь нам добавили несколько методов и можно добавлять middleware в определенном месте. Выглядит как полезная фича.

$kernel->addToMiddlewarePriorityAfter(     \Illuminate\Routing\Middleware\ValidateSignature::class,     [         \Illuminate\Cookie\Middleware\EncryptCookies::class,         \Illuminate\Contracts\Auth\Middleware\AuthenticatesRequests::class,     ], );  $kernel->addToMiddlewarePriorityBefore(     \Illuminate\Routing\Middleware\ValidateSignature::class,     [         \Illuminate\Cookie\Middleware\EncryptCookies::class,         \Illuminate\Contracts\Auth\Middleware\AuthenticatesRequests::class,     ], );

11.27 Add —json flag to queue:work command for structured logging

https://github.com/laravel/framework/pull/52887

Следующий pull request затрагивает artisan команду queue: work, добавляя новый флаг --json, который меняет output в формат JSON, что в итоге будет выглядеть следующим образом: 

Sucessful Job {   "timestamp": "2024-09-23T13:47:37.347077+00:00",   "level": "info",   "job": "App\\Jobs\\NotificarJob",   "id": "9af01732-609a-4418-86f3-904f928fd8cc",   "uuid": "88098a41-4a1e-4ea6-a4f0-58511f91e915",   "connection": "rabbitmq",   "queue": "default",   "status": "success",   "result": "deleted",   "attempts": 1,   "duration": 0.014354 }  Failed Job {   "timestamp": "2024-09-23T13:44:57.393616+00:00",   "level": "warning",   "job": "App\\Jobs\\TestJob",   "id": "12c2916c-6a04-40d7-b0d8-c48897c425a0",   "uuid": "7e719912-f6c2-4018-a1c2-c7254992f182",   "connection": "rabbitmq",   "queue": "default",   "status": "failed",   "result": "deleted",   "attempts": 3,   "exception": "App\\Exceptions\\TestException",   "message": "I have failed you.",   "duration": 0.001601 }  Job Starting {   "timestamp": "2024-09-23T13:48:37.593466+00:00",   "level": "info",   "job": "App\\Jobs\\ConsultarEnvioDocumentoAReguladorJob",   "id": "e600e9dd-474b-4e18-ad5e-a3cadd3b04c9",   "uuid": "e76cd7c8-1754-48e7-9b45-5a7ea8664d53",   "connection": "rabbitmq",   "queue": "regulador",   "status": "starting",   "attempts": 2 }

Более правильный стандартизированный путь. За этот pull request лайк!

11.28 feat: add useful defaultLocale and defaultCurrency helpers to Number facade

https://github.com/laravel/framework/pull/53101

Pull request затрагивает снова класс Number. До этого мы с вами статически видели как задается дефолтная $locale и $currency но метода для получения дефолтного значения не было и вот с этим pull request он добавлен. Кстати, что вы скажете о нейминге? У нас и сеттер без префикса set и геттер без префикса get и тем самым глядя вот на такое сразу и не поймешь это у нас геттер или все-таки здесь есть какие-то параметры и это сеттер. В общем иногда возникают вопросы. 

Number::defaultLocale() // returns default locale Number::defaultCurrency() // returns default currency

11.28 Feat: remove HasFactory in model when not required

https://github.com/laravel/framework/pull/53104

Следующий pull request. На самом деле, этот pull request мне кажется, я хотел лично сделать уже на протяжении где-то года, но никак не доходили руки и было лень. О чем он? У нас, если мы создаем модель через artisan-команду, то даже если мы не указываем, что она у нас с фабрикой, у нас все еще присутствовал trait HasFactory. Соответственно, после этого pull request этот момент исправлен. У нас trait будет присутствовать только если указан флаг, что нам необходимы также и фабрики.

php artisan make:model Post
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model; class Post extends Model {     // }
php artisan make:model Comment -f
<?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; class Comment extends Model {     /** @use HasFactory<\Database\Factories\CommentFactory> */     use HasFactory; }

11.28 Add Illuminate\Support\enum_value to resolve BackedEnum or UnitEnum to scalar

https://github.com/laravel/framework/pull/53096

Следующий pull request. И снова сахар, в этот раз helper, функция enum_value, которая у нас автоматически резолвит, независимо от того, у нас BackedEnum, либо UnitEnum, приводит его к скалярному значению. Если мы заглянем под капот в саму функцию, то увидим здесь проверку. Если у нас сразу строка, то мы ее возвращаем, либо мы с вами трансформим: если это бэки, то обращаемся к свойству value, если юнит, то к свойству name. 

if (! function_exists('Illuminate\Support\enum_value')) {     /**      * Return a scalar value for the given value that might be an enum.      *      * @internal      *      * @template TValue      * @template TDefault      *      * @param  TValue  $value      * @param  TDefault|callable(TValue): TDefault  $default      * @return ($value is empty ? TDefault : mixed)      */     function enum_value($value, $default = null)     {         if (is_string($value) && empty($value)) {             return $value;         }         return transform($value, fn ($value) => match (true) {             $value instanceof \BackedEnum => $value->value,             $value instanceof \UnitEnum => $value->name,             default => $value,         }, $default);     } }

Вот такой сахар, которым, собственно, переполнен Laravel, и в дальнейшем, я думаю, есть огромное количество возможностей для pull request, чтобы там, где под капотом Laravel выполнял данные проверки, переделать их на этот helper. Собственно, в данном pull request, где автор нашел, он уже переделал.

11.28 Introduce RouteParameter attribute

https://github.com/laravel/framework/pull/53080

Следующий pull request из Laravel 11.28 и у нас снова тема атрибутов. Как я вам говорил уже ранее, скоро атрибутов в Laravel будет огромное множество и мы практически с каждым релизом начинаем их замечать. Данный атрибут у нас называется RouteParameter  и мы благодаря ему можем сразу получить из реквеста из роута определенный параметр. Скажем у нас форм реквесты и в rules до этого нам бы пришлось обращаться к реквесту, к роуту и получать параметр Post. Теперь же мы можем просто использовать атрибут и зарезолвить параметр из роут реквеста. 

class UpdatePost extends FormRequest {     public function authorize(#[CurrentUser] User $user, #[RouteParameter('post')] Post $post): bool     {         return $post->user_id === $user->id;     }      public function rules(#[RouteParameter('post')] Post $post): array     {         return [             'slug' => ['required', 'string', Rule::unique(Post::class, 'slug')->ignore($post->id);             // ...         ];     } }

Взглянем на то, что происходит под капотом: видим обращение из контейнера к реквесту, далее как раз route и получение параметра из роута:

   /**      * Resolve the route parameter.      *      * @param  self  $attribute      * @param  \Illuminate\Contracts\Container\Container  $container      * @return mixed      */     public static function resolve(self $attribute, Container $container)     {         return $container->make('request')->route($attribute->parameter);     }

11.28 Add CollectedBy attribute

https://github.com/laravel/framework/pull/53122

Снова атрибуты, и на этот раз интересный лично для меня атрибут, чтобы в рамках модели мы сразу могли указать, в какую коллекцию мы будем маппить результат с записями. До этого тоже не составляло труда это делать через метод newCollection, который нужно было перезаписать, но всегда у меня возникали сложности, как он точно там называется, что именно и в каком виде должен возвращать, так как в Laravel иногда в этом бывает каша. 

#[CollectedBy(PostCollection::class)] class Post {     // ... }

Теперь же все будет просто: атрибут, указываем какая коллекция и дальше с ней взаимодействуем.

11.28 Add Tailwind, «composer run dev»

https://github.com/laravel/laravel/pull/6463

Двигаемся дальше по апдейту 11.28, но это уже не репозиторий Laravel/Framework, это уже Laravel/Laravel, то есть сам скелет. 

И здесь Тейлор добавил новый скрипт в Composer, называется  он Dev, с помощью него мы можем теперь запускать composer run dev, и он будет выполнять все необходимые нам команды для Dev разработки. А именно сразу запускать виртуальный сервер (php artisan serve), очереди (php artisan pail) и Vite в режиме Dev. Как видим output одной командой, мы все запустили и погнали работать!

11.29 Add directive @bool to Blade

https://github.com/laravel/framework/pull/53179

Первый pull request в Laravel 11.29: это новая директива @bool для Blade. В чем ее особенность? Если мы в Blade взаимодействуем с AlpineJS либо просто с JS и пытаемся где-то вывести булево значение, то нам всегда приходилось это делать с проверкой: если это true, то мы выводим строкой true, либо, соответственно, строкой false. Эта директива все сделает за нас и будет делать echo true либо echo false. Ничего особенного, просто очередной помощник.

JS

<script>     let config = {         isActive: @bool($isActive),         hasAccess: @bool($hasAccess)     }; </script>

Alpine

<div x-data="{ isActive: @bool($isActive) }">     <button :class="{ 'active': isActive }">Toggle </button> </div>

Bootstrap:

<div class="dropdown">   <button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="@bool($hasPopup)" aria-expanded="@bool($isExpanded)">     Dropdown button   </button>   <div class="dropdown-menu" aria-labelledby="dropdownMenuButton">     <a class="dropdown-item" href="#">Action</a>     <a class="dropdown-item" href="#">Another action</a>     <a class="dropdown-item" href="#">Something else here</a>   </div> </div>

11.29 Add waitUntil method to Process

https://github.com/laravel/framework/pull/53236

У нас уже был процесс с новым методом stop, также появился новый метод waitUntil.

Если мы имеем дело с long-running процессом, мы с вами также можем динамически указать сколько времени мы можем ожидать его завершения. 

11.29 Add helper method to determine stray request prevention state

https://github.com/laravel/framework/pull/53232

И напоследок по релизу 11.29 и дайджесту за октябрь — это pull request, который затрагивает HTTP-клиент и добавляет метод preventingStrayRequests. На самом деле, мне кажется, он уже был. Но как бы там ни было, видим, что он добавлен в 11 версию. И тем самым он предостерегает нас, чтобы не было запросов к каким-либо внешним API. Это будет полезно на уровне тестов, чтобы мы были уверены, что у нас все запросы фейковые, а не реальные. 

Напоминаю вам, что 30 октября выходит викторина «Своя игра», уже третий выпуск. Всех вас обязательно ждем в прямом эфире.

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


ссылка на оригинал статьи https://habr.com/ru/articles/854716/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *