Разрешение конфликтов трейтов
Часть раздела Объектно-ориентированное программирование путешествия по PHP на Coddy. Урок 53 из 91.
Когда два трейта определяют methods с одним и тем же именем, PHP вызывает фатальную ошибку. Вы должны явно указать PHP, как обрабатывать conflict, используя операторы insteadof и as.
<?php
trait FileLogger {
public function log(string $message): void {
echo "File: $message";
}
}
trait DatabaseLogger {
public function log(string $message): void {
echo "DB: $message";
}
}
class Application {
use FileLogger, DatabaseLogger {
FileLogger::log insteadof DatabaseLogger;
DatabaseLogger::log as logToDatabase;
}
}
$app = new Application();
$app->log("Error occurred");
$app->logToDatabase("Error occurred");
Вывод:
File: Error occurred
DB: Error occurredОператор insteadof выбирает, method какого трейта использовать, когда возникает conflict. В этом примере FileLogger::log побеждает и становится default method log(). Оператор as создаёт alias, позволяя обращаться к method другого трейта под другим именем.
Вы также можете использовать as, чтобы изменить видимость метода:
<?php
trait Greeting {
public function sayHello(): void {
echo "Hello!";
}
}
class Person {
use Greeting {
sayHello as private;
}
}
Это делает sayHello() private внутри класса Person, хотя в трейте он public. Разрешение конфликтов даёт точный контроль над тем, как методы трейта интегрируются в ваши классы.
Задание
ЛегкоДавайте создадим систему уведомлений, в которой разные каналы могут отправлять сообщения, но нам нужно разрешать конфликты, когда несколько трейтов предоставляют один и тот же метод.
Вы распределите код по четырём файлам:
EmailNotifier.php: создайте трейт с названиемEmailNotifierи методомnotify(string $message), который возвращает"Email: [message]".SmsNotifier.php: создайте трейт с названиемSmsNotifierи методомnotify(string $message), который возвращает"SMS: [message]".AlertService.php: создайте classAlertService, использующий оба трейта. Поскольку оба трейта имеют методnotify(), вам потребуется разрешить этот конфликт:- используйте
EmailNotifier::notifyкак методnotify()по умолчанию; - создайте alias
notifyBySmsдля методаSmsNotifier::notify.
notifyAll(string $message), который вызывает оба метода notification и возвращает их combined в отдельных строках.- используйте
main.php: подключите все необходимые файлы и создайте instanceAlertService. Вы получите один input: строку message. Выведите три строки:- результат calling
notify()с message; - результат calling
notifyBySms()с message; - результат calling
notifyAll()с message.
- результат calling
Это демонстрирует, как insteadof разрешает, метод какого трейта побеждает при конфликте имён, тогда как as позволяет сохранить доступ к методу другого трейта под другим именем.
Попробуйте сами
<?php
require_once 'AlertService.php';
// Прочитать ввод
$message = trim(fgets(STDIN));
// TODO: Создать экземпляр AlertService
// TODO: Вывести результат вызова notify() с сообщением
// TODO: Вывести результат вызова notifyBySms() с сообщением
// TODO: Вывести результат вызова notifyAll() с сообщением
?>В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
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