Menu
Coddy logo textTech

Введение в трейты

Часть раздела Объектно-ориентированное программирование путешествия по PHP на Coddy — урок 51 из 91.

PHP поддерживает только одиночное наследование — класс может расширять только один родительский класс. Но что, если вам нужно использовать общую функциональность в нескольких несвязанных классах? Именно здесь на помощь приходят traits.

Трейт (trait) — это механизм повторного использования кода, который позволяет определять методы и свойства, которые могут быть вставлены в несколько классов. Представьте трейты как копирование и вставку на уровне языка — код из трейта становится частью класса, который его использует.

<?php
trait Timestampable {
    private string $createdAt;
    
    public function setCreatedAt(): void {
        $this->createdAt = date('Y-m-d H:i:s');
    }
    
    public function getCreatedAt(): string {
        return $this->createdAt;
    }
}

class Article {
    use Timestampable;
    
    public function __construct(public string $title) {
        $this->setCreatedAt();
    }
}

$article = new Article("PHP Traits");
echo $article->getCreatedAt();

Ключевое слово use внутри класса импортирует члены трейта. Теперь Article имеет доступ к setCreatedAt() и getCreatedAt() так, как если бы они были определены непосредственно в классе.

Один и тот же трейт может использоваться в совершенно не связанных классах — классе Comment, классе User или любом другом классе, которому требуется функциональность меток времени. Это решает проблему ограничения одиночного наследования, позволяя горизонтально разделять код в иерархии ваших классов.

challenge icon

Задание

Легко

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

Вы организуете свой код в трех файлах:

  • Greetable.php — Создайте трейт с именем Greetable, который обеспечивает функциональность приветствия. Трейт должен иметь:
    • Приватное свойство $greeting (string)
    • Метод setGreeting(string $greeting), который сохраняет приветственное сообщение
    • Метод greet(), который возвращает приветственное сообщение
  • Person.php — Создайте класс Person, который использует трейт Greetable. Подключите файл трейта и используйте продвижение свойств в конструкторе (constructor promotion) для определения публичного свойства $name. В конструкторе вызовите setGreeting(), чтобы установить приветствие в значение "Hello, I'm [name]".
  • Robot.php — Создайте класс Robot, который также использует трейт Greetable. Подключите файл трейта и используйте продвижение свойств в конструкторе для определения публичного свойства $model. В конструкторе вызовите setGreeting(), чтобы установить приветствие в значение "Beep boop, I am model [model]".

В main.php подключите оба файла классов. Вы получите два входных значения: имя человека и номер модели робота. Создайте экземпляры обоих классов и выведите их приветствия на отдельных строках.

Это демонстрирует мощь трейтов — Person и Robot являются совершенно несвязанными классами без общего родителя, однако они оба получают одну и ту же функциональность приветствия через трейт. Каждый класс настраивает использование этой функциональности по-своему.

Шпаргалка

Трейт (trait) — это механизм повторного использования кода, который позволяет совместно использовать методы и свойства в нескольких несвязанных классах, решая ограничение PHP на одиночное наследование.

Определите трейт с помощью ключевого слова trait:

<?php
trait Timestampable {
    private string $createdAt;
    
    public function setCreatedAt(): void {
        $this->createdAt = date('Y-m-d H:i:s');
    }
    
    public function getCreatedAt(): string {
        return $this->createdAt;
    }
}

Используйте трейт в классе с помощью ключевого слова use:

class Article {
    use Timestampable;
    
    public function __construct(public string $title) {
        $this->setCreatedAt();
    }
}

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

Попробуйте сами

<?php

require_once 'Person.php';
require_once 'Robot.php';

// Чтение входных данных
$name = trim(fgets(STDIN));
$model = trim(fgets(STDIN));

// TODO: Создать экземпляр Person с заданным именем
// TODO: Создать экземпляр Robot с заданной моделью
// TODO: Вывести приветствие Person
// TODO: Вывести приветствие Robot (на новой строке)

?>
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование