Продвижение свойства конструктора в PHP 8

Если и есть что-то лишнее и скучное в объектно-ориентированном программировании, так это определение конструкторов объектов. В большинстве случаев, большая часть написанного кода — это информация, которую интерпретатор или компилятор может понять самостоятельно.

⚠️ Читайте больше моих статей о технике и бизнесе в моем личном блоге! ⚠️

В этой серии статей я снова рассказываю вам о новых возможностях последней версии PHP. Давайте вместе узнаем, что нового предлагает нам PHP версии 8 и как это может быть полезно для нас.

То, что я только что изложил, не имеет особых нюансов, это правда. Но если я просмотрю кодовые базы своих предыдущих проектов, то большинство конструкторов, которые я написал, используются только для инициализации переменных экземпляра (свойств).

Давайте рассмотрим пример на PHP, чтобы проиллюстрировать это:

<?php

class MyClass extends ParentClass {
    private string $title;
    private bool $isUnique;
    private bool $isVariadic;

    public function __construct(
        string $title,
        bool $isUnique = false,
        bool $isVariadic = false,
        ?string $desc = null,
    ) {
        parent::__construct($text);

        $this->title = $title;
        $this->isUnique = $isUnique;
        $this->isVariadic = $variadic;
    }
}
Вход в полноэкранный режим Выйти из полноэкранного режима

Вот типичный пример всего того, что я описал выше. Есть три свойства, которые повторяются в качестве аргументов конструктора и дважды при присваивании внутри конструктора. Типы также повторяются дважды.

Кажется, что видишь почти один и тот же код три раза. Это скучно читать, но еще более утомительно писать или сопровождать: такой способ ведения дел увеличивает риск ошибки. Почему? Если я изменяю какое-либо из свойств экземпляра, мне обязательно нужно не забыть изменить объявления и/или назначения свойств конструктора.

PHP 8 предлагает решение этой проблемы за счет продвижения свойств конструктора.

<?php

class MyClass extends ParentClass {
    public function __construct(
        private string $title,
        private bool $isUnique = false,
        private bool $isVariadic = false,
        ?string $desc = null,
    ) {
        parent::__construct($text);
    }
}
Вход в полноэкранный режим Выход из полноэкранного режима

Эти два примера идентичны. Но посмотрите, как продвинутые свойства помогают сделать код проще, читабельнее и умнее. Вся информация, необходимая для понимания кода, находится в одной строке, а не разбита на три отдельных места.

Опять же, это не прорывная функция или что-то действительно новое. Другие языки, такие как TypeScript, уже давно имеют такую возможность.

Применяется не во всех ситуациях

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

Эта функциональность означает: автоматически создавать переменные экземпляра и присваивать их. Что невозможно, например, в абстрактном конструкторе.

<?php

interface MyInterface {
    public function __construct(
        private string $title, // Erreur
    ) {}
}

abstract class MyClass {
    abstract public function __construct(
        private string $title, // Erreur
    ) {}
}
Вход в полноэкранный режим Выход из полноэкранного режима

Другой случай, когда эта функциональность не может быть использована, — это callables. Тип callable не поддерживается для свойств метода. Поэтому невозможно продвинуть свойство callable, так как оно не существует.

<?php

class MyClass {
    public function __construct(
        private callable $fn, // Erreur
    ) {}
}
Вход в полноэкранный режим Выход из полноэкранного режима

Я бы также добавил, что продвигаемые свойства нельзя использовать с неявными nullable типами. Вернее, нулевой тип не может быть неявно связан с продвигаемым свойством.

<?php

class MyClass {
    public function __construct(
        private string $desc = null, // Erreur
        private ?string $text = null, // OK
    ) {}
}
Вход в полноэкранный режим Выход из полноэкранного режима

Пока вы явно указываете, что свойство может быть null, PHP не будет возражать.

Продвигаемые свойства улучшают качество кода

Я часто использовал этот метод в TypeScript, и я нахожу продвижение свойств конструктора действительно полезным в моей повседневной жизни как разработчика. Позвольте мне объяснить: во-первых, я пишу в три раза меньше кода. Затем, мне легче читать и понимать код для данной переменной экземпляра.

<?php

class MyClass extends ParentClass {
    public function __construct(
        private string $title,
        private bool $isUnique = false,
        private bool $isVariadic = false,
        string $desc = null,
    ) {
        parent::__construct($text);
    }
}
Вход в полноэкранный режим Выход из полноэкранного режима

Но этот метод также дает мне информацию о других свойствах конструктора. В примере выше вы заметили свойство $desc? Мы не используем для него продвижение свойств конструктора, что дает мне еще одну часть информации: $desc — это не классический случай переменной экземпляра, разработчику нужно было сделать с ней что-то другое, и было бы интересно посмотреть, что это такое.

Это контекстуально: поскольку разработчик, написавший код, использовал продвигаемые свойства, почему он не продвинул все свойства? Возможно, потому что у него не было выбора. Возможно, у него были особые тесты для этого свойства. Или, как в нашем примере, ему нужно было передать его родительскому классу. Это делает код умнее, но это также делает чтение кода умнее, указывая точки, на которые следует обратить внимание.

И поскольку это контекстуально, как вы можете себе представить, рассуждения, которые я только что описал, будут работать не всегда. Если ни одно из свойств не продвинуто, это не обязательно означает, что все свойства этого конструктора являются частными случаями. Возможно, разработчик, написавший код, еще не знает о существовании продвигаемых свойств, возможно, он не хочет использовать эту возможность, а может быть, его код был написан до появления PHP 8. В общем, вы поняли, о чем идет речь.

Я закончу эту статью напоминанием о том, что Promoted Properties — это ленивая функция, а разработчики ленивы, и я уверен, что вы все с удовольствием примете ее в своих будущих проектах. А пока, вот немного чтения:

  • Разделите свой код!
  • Именованные аргументы в PHP8

Оцените статью
devanswers.ru
Добавить комментарий