トレイト入門
CoddyのPHPジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 51/91。
PHPは単一継承のみをサポートしています。つまり、クラスは1つの親クラスのみを継承できます。しかし、関連のない複数のクラス間で機能を共有する必要がある場合はどうすればよいでしょうか?そこで登場するのがトレイト(traits)です。
トレイトは、複数のクラスに挿入できるメソッドやプロパティを定義できるようにする、コード再利用のためのメカニズムです。トレイトを言語レベルでのコピー&ペーストと考えてください。トレイトのコードは、それを使用するクラスの一部になります。
<?php
trait Timestampable {
private string $createdAt;
public function setCreatedAt(): void {
$this->createdAt = date('Y-m-d H:i:s');
}
public function getCreatedAt(): string {
return $this->createdAt;
}
}
class Article {
use Timestampable;
public function __construct(public string $title) {
$this->setCreatedAt();
}
}
$article = new Article("PHP Traits");
echo $article->getCreatedAt();
クラス内の use キーワードは、トレイトのメンバーをインポートします。これで、Article は setCreatedAt() と getCreatedAt() に、あたかもそれらがクラス内で直接定義されているかのようにアクセスできるようになります。
同じトレイトを、Commentクラス、Userクラス、またはタイムスタンプ機能を必要とするその他のクラスなど、全く関連のないクラスで使用することができます。これにより、クラス階層全体でコードを水平方向に共有できるようになり、単一継承の制限が解決されます。
チャレンジ
簡単トレイトを使用して、関連のないクラス間で機能を共有する方法を示す、シンプルな挨拶システムを構築しましょう。挨拶機能を提供するトレイトを作成し、それを2つの全く異なるクラスで使用します。
コードを3つのファイルに分けて構成します:
Greetable.php— 挨拶機能を提供するGreetableという名前のトレイトを作成します。このトレイトには以下を含める必要があります:- プライベートプロパティ
$greeting(string) - 挨拶メッセージを保存するメソッド
setGreeting(string $greeting) - 挨拶メッセージを返すメソッド
greet()
- プライベートプロパティ
Person.php—Greetableトレイトを使用するPersonクラスを作成します。トレイトファイルを読み込み、コンストラクタのプロパティ昇格(constructor promotion)を使用してパブリックな$nameプロパティを定義します。コンストラクタ内でsetGreeting()を呼び出し、挨拶を"Hello, I'm [name]"に設定します。Robot.php— 同じくGreetableトレイトを使用するRobotクラスを作成します。トレイトファイルを読み込み、コンストラクタのプロパティ昇格を使用してパブリックな$modelプロパティを定義します。コンストラクタ内でsetGreeting()を呼び出し、挨拶を"Beep boop, I am model [model]"に設定します。
main.php で、両方のクラスファイルを読み込みます。2つの入力(人の名前とロボットのモデル番号)を受け取ります。両方のクラスのインスタンスを作成し、それぞれの挨拶を別々の行に出力してください。
これはトレイトの強力さを示しています。Person と Robot は共通の親を持たない全く無関係なクラスですが、トレイトを通じて同じ挨拶機能を得ることができます。各クラスは、その機能を独自の方法でカスタマイズして使用します。
チートシート
トレイトは、コード再利用のための仕組みであり、複数の関連のないクラス間でメソッドやプロパティを共有することを可能にし、PHPの単一継承の制限を解決します。
traitキーワードを使用してトレイトを定義します:
<?php
trait Timestampable {
private string $createdAt;
public function setCreatedAt(): void {
$this->createdAt = date('Y-m-d H:i:s');
}
public function getCreatedAt(): string {
return $this->createdAt;
}
}
useキーワードを使用して、クラス内でトレイトを使用します:
class Article {
use Timestampable;
public function __construct(public string $title) {
$this->setCreatedAt();
}
}
トレイトのメソッドとプロパティは、あたかもそのクラス内で直接定義されているかのように、クラスの一部になります。複数の関連のないクラスが同じトレイトを使用して、クラス階層を越えて水平方向に機能を共有できます。
自分で試してみよう
<?php
require_once 'Person.php';
require_once 'Robot.php';
// 入力を読み込む
$name = trim(fgets(STDIN));
$model = trim(fgets(STDIN));
// TODO: 指定された名前でPersonインスタンスを作成する
// TODO: 指定されたモデルでRobotインスタンスを作成する
// TODO: Personの挨拶を表示する
// TODO: Robotの挨拶を表示する(改行して)
?>このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。