Menu
Coddy logo textTech

Разрешение конфликтов трейтов

Часть раздела Объектно-ориентированное программирование путешествия по 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. Разрешение конфликтов даёт точный контроль над тем, как методы трейта интегрируются в ваши классы.

challenge icon

Задание

Легко

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

Вы распределите код по четырём файлам:

  • EmailNotifier.php: создайте трейт с названием EmailNotifier и методом notify(string $message), который возвращает "Email: [message]".
  • SmsNotifier.php: создайте трейт с названием SmsNotifier и методом notify(string $message), который возвращает "SMS: [message]".
  • AlertService.php: создайте class AlertService, использующий оба трейта. Поскольку оба трейта имеют метод notify(), вам потребуется разрешить этот конфликт:
    • используйте EmailNotifier::notify как метод notify() по умолчанию;
    • создайте alias notifyBySms для метода SmsNotifier::notify.
    Также добавьте метод notifyAll(string $message), который вызывает оба метода notification и возвращает их combined в отдельных строках.
  • main.php: подключите все необходимые файлы и создайте instance AlertService. Вы получите один input: строку message. Выведите три строки:
    • результат calling notify() с message;
    • результат calling notifyBySms() с message;
    • результат calling notifyAll() с message.

Это демонстрирует, как insteadof разрешает, метод какого трейта побеждает при конфликте имён, тогда как as позволяет сохранить доступ к методу другого трейта под другим именем.

REQUIRED OUTPUT FORMAT: [Your translated content here]

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

<?php
require_once 'AlertService.php';

// Прочитать ввод
$message = trim(fgets(STDIN));

// TODO: Создать экземпляр AlertService

// TODO: Вывести результат вызова notify() с сообщением

// TODO: Вывести результат вызова notifyBySms() с сообщением

// TODO: Вывести результат вызова notifyAll() с сообщением
?>
quiz iconПроверьте себя

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

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

Потренируйтесь самостоятельно: Онлайн-компилятор PHP