Введение в трейты
Часть раздела Объектно-ориентированное программирование путешествия по 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 или любом другом классе, которому требуется функциональность меток времени. Это решает проблему ограничения одиночного наследования, позволяя горизонтально разделять код в иерархии ваших классов.
Задание
ЛегкоДавайте создадим простую систему приветствий, которая демонстрирует, как трейты позволяют разделять функциональность между несвязанными классами. Вы создадите трейт, обеспечивающий возможность приветствия, а затем используете его в двух совершенно разных классах.
Вы организуете свой код в трех файлах:
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 (на новой строке)
?>В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыВведение в ООПКлассы и объектыКлючевое слово $thisМетодыСвойстваКонструктор (__construct)Деструктор (__destruct)Итоги — Простой калькулятор4Наследование
Основы наследованияКлючевое слово parent::Переопределение методовКлючевое слово finalАбстрактные классыИтоги — Иерархия сотрудников7Инкапсуляция
Public, Protected, PrivateПодробный разбор модификаторов доступаГеттеры и сеттерыСокрытие данныхConstructor Promotion (8.0)Итоги — Система учета студентов10Продвинутые концепции ООП
Композиция против наследованияВнедрение зависимостейАнонимные классыПеречисления (PHP 8.1)Файберы (PHP 8.1)Глубокое погружение в клонирование объектовГенераторы и итераторы13Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикПаттерн Репозиторий2Пространства имен и автозагрузка
Введение в пространства именКлючевое слово useСтандарт автозагрузки PSR-4Автозагрузчик ComposerИтоги: структурированный проект5Интерфейсы и контракты
Введение в интерфейсыРеализация интерфейсовРеализация нескольких интерфейсовИнтерфейс против абстрактного классаType Hinting с интерфейсамиИтоги — Калькулятор фигур8Магические методы
Введение в магические методы__toString и __debugInfo__get, __set, __isset, __unset__call и __callStatic__clone и клонирование объектов__serialize и __unserializeИтоги — Кастомная коллекция11Система типов и обработка ошибок
Объявление типовNullable-типыТипы объединения и пересеченияКлассы исключенийИерархия пользовательских исключенийTry, Catch, FinallyИтоги — Валидатор форм14Проект: Управление библиотекой
Обзор проектаКлассы Book и User3Свойства классов
Свойства экземпляра и статические свойстваКонстанты в классахСтатические методы и свойстваПриватные и защищенные свойстваСвойства Readonly (PHP 8.1)Итоги — Менеджер банковского счета6Полиморфизм
Снова о переопределении методовПолиморфизм через интерфейсыType Hinting и Union TypesПозднее статическое связываниеИтоги — Payment Processor9Трейты
Введение в трейтыИспользование нескольких трейтовРазрешение конфликтов трейтовАбстрактные методы в трейтахТрейты и наследование12Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн ObserverПаттерн Strategy