Как стать автором
Обновить

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

Время на прочтение13 мин
Количество просмотров3K

Всем привет!

Это дайджест новостей от 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 октября выходит викторина "Своя игра", уже третий выпуск. Всех вас обязательно ждем в прямом эфире.

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

Теги:
Хабы:
+12
Комментарии2

Публикации

Истории

Работа

PHP программист
109 вакансий

Ближайшие события

28 ноября
Конференция «TechRec: ITHR CAMPUS»
МоскваОнлайн
2 – 18 декабря
Yandex DataLens Festival 2024
МоскваОнлайн
11 – 13 декабря
Международная конференция по AI/ML «AI Journey»
МоскваОнлайн
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань