Menu
Coddy logo textTech

トレイトの競合解決

CoddyのPHPジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 53/91。

2つのトレイトが同じ名前のmethodsを定義すると、PHPは致命的なエラーを発生させます。このconflictをどのように処理するかを、insteadof演算子とas演算子を使ってPHPに明示的に指示する必要があります。

<?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 を使用するかを選択します。この例では、FileLogger::log が優先され、デフォルトの log() method になります。as 演算子は alias を作成し、もう一方のトレイトの method に別の名前でアクセスできるようにします。

asを使ってメソッドの可視性を変更することもできます。

<?php
trait Greeting {
    public function sayHello(): void {
        echo "Hello!";
    }
}

class Person {
    use Greeting {
        sayHello as private;
    }
}

これにより、トレイトでは public であるにもかかわらず、sayHello()Person クラス内で private になります。競合の解決によって、トレイトのメソッドをクラスに統合する方法を細かく制御できます。

challenge icon

チャレンジ

簡単

異なるチャネルからメッセージを送信できる通知システムを構築しましょう。ただし、複数のトレイトが同じメソッド名を提供する場合は、conflict を解決する need があります。

コードを4つのファイルに整理します。

  • EmailNotifier.phpEmailNotifierというトレイトをCreateし、notify(string $message)というmethodを定義します。このmethodは"Email: [message]"を返します。
  • SmsNotifier.phpSmsNotifierというトレイトをCreateし、notify(string $message)というmethodを定義します。このmethodは"SMS: [message]"を返します。
  • AlertService.php:bothのトレイトを使用するAlertService classをCreateします。bothのトレイトにはnotify() methodがあるため、このconflictをresolveするneedがあります。
    • デフォルトのnotify() methodとしてEmailNotifier::notifyを使用します
    • SmsNotifier::notify methodにnotifyBySmsというaliasをCreateします
    また、bothのnotification methodsをcallingし、それらを別々の行にcombinedして返すnotifyAll(string $message) methodも追加します。
  • main.php:needなすべてのファイルをincludeし、AlertService instanceをCreateします。1つのinputとしてmessage stringを受け取ります。3行をPrintします。
    • messageを指定してnotify()をcallingした結果
    • messageを指定してnotifyBySms()をcallingした結果
    • messageを指定してnotifyAll()をcallingした結果

これは、名前のconflictがある場合にinsteadofがどのトレイトのmethodを優先するかをresolveし、asによってもう一方のトレイトのmethodにも別の名前でアクセスできることを示しています。

自分で試してみよう

<?php
require_once 'AlertService.php';

// 入力を読み取る
$message = trim(fgets(STDIN));

// TODO: AlertService のインスタンスを作成する

// TODO: message を渡して notify() を呼び出した結果を出力する

// TODO: message を渡して notifyBySms() を呼び出した結果を出力する

// TODO: message を渡して notifyAll() を呼び出した結果を出力する
?>
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: PHPオンラインコンパイラ