Всем привет!
Это дайджест новостей от 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/
Добавить комментарий