Абстрактные методы в трейтах
Часть раздела Объектно-ориентированное программирование путешествия по PHP на Coddy. Урок 54 из 91.
Traits могут предоставлять готовые к использованию методы, но иногда вам нужно, чтобы class, использующий trait, реализовал определённую функциональность. В этом случае полезны абстрактные методы в traits — они определяют контракт, которому должен соответствовать использующий их class.
Когда trait объявляет абстрактный метод, любой класс, использующий этот trait, должен реализовать его:
<?php
trait Notifiable {
abstract public function getEmail(): string;
public function sendNotification(string $message): void {
echo "Sending to " . $this->getEmail() . ": $message";
}
}
class User {
use Notifiable;
public function __construct(private string $email) {}
public function getEmail(): string {
return $this->email;
}
}
$user = new User("john@example.com");
$user->sendNotification("Welcome!");
Вывод:
Sending to john@example.com: Welcome!Трейт предоставляет метод sendNotification(), но полагается на реализацию getEmail() классом. Это создаёт мощный шаблон, в котором трейт обрабатывает общую логику, делегируя специфичные для класса детали реализующему его классу.
Если class использует trait, не реализуя abstract method, PHP выдаёт фатальную ошибку. Это гарантирует, что traits могут безопасно зависеть от существования определённых методов, делая ваш код более предсказуемым и удобным в сопровождении.
Задание
ЛегкоДавайте создадим систему ценообразования, в которой разные типы продуктов по-разному рассчитывают свои итоговые цены, но используют общую логику скидок через trait с abstract методом.
Вы организуете код в трёх файлах:
Discountable.php: Create trait с названиемDiscountable, который предоставляет функциональность скидок. Trait должен содержать:- abstract method
getBasePrice(): float, который должны Implement class, использующие этот trait - method
applyDiscount(int $percent), который calculate и возвращает price после applying percentage скидки к базовой цене - method
getFinalPrice(int $percent), который возвращает formatted строку:"Final price: $[discounted_price]"с 2 десятичными знаками
- abstract method
Product.php: CreateProductclass, использующий traitDiscountable. Подключите файл trait. Используйте продвижение constructor, чтобы Declare private$name(string) и private$price(float). Implement requiredgetBasePrice()method, чтобы вернуть price продукта.main.php: Подключите файл Product. Вы получите три inputs: название продукта, price и percentage скидки. Create экземплярProductи Print две строки:- Базовая цена в formatted виде
"Base: $[price]"с 2 десятичными знаками - result calling
getFinalPrice()с percentage скидки
- Базовая цена в formatted виде
Этот pattern обладает большой силой, потому что trait Discountable может использоваться любым class — продуктами, сервисами, подписками, — если они Implement getBasePrice(). Trait предоставляет общую логику скидок, а каждый class определяет, откуда берётся его базовая цена.
Попробуйте сами
<?php
require_once 'Product.php';
// Считать входные данные
$name = trim(fgets(STDIN));
$price = floatval(trim(fgets(STDIN)));
$discountPercent = intval(trim(fgets(STDIN)));
// TODO: Создать экземпляр Product с именем и ценой
// TODO: Вывести базовую цену в формате "Base: $[price]" с 2 знаками после запятой
// TODO: Вывести результат вызова getFinalPrice() с процентом скидки
?>В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыВведение в ООПКлассы и объектыКлючевое слово $thisМетодыСвойстваКонструктор (__construct)Деструктор (__destruct)Повторение — простой калькулятор4Наследование
Основы наследованияКлючевое слово parent::Переопределение методовКлючевое слово finalАбстрактные классыПовторение — иерархия сотрудников7Инкапсуляция
Public, Protected, PrivateМодификаторы доступа подробноГеттеры и сеттерыСокрытие информацииПродвижение конструктора (8.0)Повторение — система учёта студентов2Пространства имён и автозагрузка
Введение в пространства имёнКлючевое слово useСтандарт автозагрузки PSR-4Автозагрузчик ComposerПовторение — структурированный проект5Интерфейсы и контракты
Введение в интерфейсыРеализация интерфейсовРеализация нескольких интерфейсовИнтерфейс и абстрактный классАннотация типов с интерфейсамиПовторение — калькулятор фигур8Магические методы
Введение в магические методы__toString и __debugInfo__get, __set, __isset, __unset__call и __callStatic__clone и клонирование объектов__serialize и __unserializeПовторение — пользовательская коллекция3Свойства классов
Свойства экземпляра и статические свойстваКонстанты в классахСтатические методы и свойстваПриватные и защищённые свойстваСвойства только для чтения (PHP 8.1)Повторение — менеджер банковского счёта6Полиморфизм
Повторение переопределения методовПолиморфизм через интерфейсыАннотации типов и объединённые типыПозднее статическое связываниеПовторение — обработчик платежей9Трейты
Введение в трейтыИспользование нескольких трейтовРазрешение конфликтов трейтовАбстрактные методы в трейтахТрейты и наследование12Паттерны проектирования, часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн ObserverПаттерн StrategyПотренируйтесь самостоятельно: Онлайн-компилятор PHP