トレイトの競合解決
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 occurredinsteadof 演算子は、競合がある場合にどのトレイトの 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 になります。競合の解決によって、トレイトのメソッドをクラスに統合する方法を細かく制御できます。
チャレンジ
簡単異なるチャネルからメッセージを送信できる通知システムを構築しましょう。ただし、複数のトレイトが同じメソッド名を提供する場合は、conflict を解決する need があります。
コードを4つのファイルに整理します。
EmailNotifier.php:EmailNotifierというトレイトをCreateし、notify(string $message)というmethodを定義します。このmethodは"Email: [message]"を返します。SmsNotifier.php:SmsNotifierというトレイトをCreateし、notify(string $message)というmethodを定義します。このmethodは"SMS: [message]"を返します。AlertService.php:bothのトレイトを使用するAlertServiceclassをCreateします。bothのトレイトにはnotify()methodがあるため、このconflictをresolveするneedがあります。- デフォルトの
notify()methodとしてEmailNotifier::notifyを使用します SmsNotifier::notifymethodにnotifyBySmsというaliasをCreateします
notifyAll(string $message)methodも追加します。- デフォルトの
main.php:needなすべてのファイルをincludeし、AlertServiceinstanceをCreateします。1つのinputとしてmessage stringを受け取ります。3行をPrintします。- messageを指定して
notify()をcallingした結果 - messageを指定して
notifyBySms()をcallingした結果 - messageを指定して
notifyAll()をcallingした結果
- messageを指定して
これは、名前の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() を呼び出した結果を出力する
?>このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
自分で練習してみよう: PHPオンラインコンパイラ