オープンソースのWeb開発向けスクリプト言語「PHP」の文法を一から学ぶための入門連載。今回は、クラスに対して横断的に機能を追加できる「トレイト」について解説します。
オープンソースのWeb開発向けスクリプト言語「PHP」の文法を一から学ぶための入門連載「Web業界で働くためのPHP入門」。
今回は、クラスに対して横断的に機能を追加できる「トレイト」について解説します。
トレイトは、継承とはまた別の方法でクラスを拡張できる仕組みです。最初に少し概論的な話をしておきましょう。
連載第17回でクラスを拡張できる仕組みとして継承を解説しました。その継承は親クラスを文字通り引き継ぎ、そこに子クラス独自のプロパティやメソッドを追加することで拡張します。例えば、スポーツ選手を表すSportsPlayerクラスがあったとします(リスト1)。
<?php class SportsPlayer { //名前のプロパティ。 private $name; //コンストラクタ。名前プロパティに値をセットする。 public function __construct(string $name) { $this->name = $name; } //名前プロパティのゲッタ。 public function getName():string { return $this->name; } }
これを継承したTennisPlayerクラス、HandballPlayerクラス、BaseballPlayerクラスを考えます。それぞれクラス名の通り、「テニス選手」「ハンドボール選手」「野球選手」を表します。それぞれのクラスには、その球技で使う道具、例えばテニスならラケット、野球ならバットとグローブを表すプロパティ(ハンドボールは道具を使いません)と、その球技独特の何かメソッドを追加するとします。
ここで、メソッドとして、その球技の主要な動作を考えます。例えば、テニスならば「打つ」で、ハンドボールならば「投げる」です。野球にはこの両方の動作が含まれます(図1)。
ここで、もう一段階考えます。テニスと野球には同じ動作(=処理)である「打つ」が含まれています。共通の処理がある場合は、それは親クラスに記述した方が継承のメリットを生かせます。そのように考えてSportsPlayerクラスに「打つ」を追加したとします(図2)。
すると、問題が生じます。HandballPlayerクラスにも「打つ」が含まれてしまうことになります。ハンドボールに「打つ」は不要です。同様に、「投げる」を親クラスに追加したら、今度はTennisPlayerクラスに不要な処理が含まれてしまいます。親から子へ、子から孫へと内容を引き継ぐ継承は、縦方向(垂直方向)のクラスの拡張といえますが、垂直方向故に、このような問題が生じます。
この問題を解決するのが、トレイトです。トレイトは水平方向のクラスの拡張といえます。それは、各クラスにプロパティとメソッドのカタマリを、あたかも機能拡張のように追加できます。例えば、「打つ」というトレイトと「投げる」というトレイトの2個を用意しておき、TennisPlayerクラスには「打つ」トレイトを組み込みます。HandballPlayerクラスには「投げる」トレイトを組み込みます。そして、BaseballPlayerクラスには両方のトレイトを組み込みます(図3)。
では、実際にソースコードでみていきましょう。まず、「打つ」を表すトレイトであるHitTraitトレイトを作成します。これは、リスト2のようになります。
<?php trait HitTrait // (1) { public function hit():void // (2) { print(__CLASS__."がボールを打ちます。<br>"); // (3) } }
トレイトを作成するには、(1)のように「trait」宣言を使います。トレイト名は、HitTraitのように「○○Trait」とするのが習わしです。
trait ○○Trait
{
プロパティ
メソッド
:
}
トレイトはクラス機能の一部を切り出したものですので、クラス同様にプロパティやメソッドを記述できます。リスト2では「打つ」を表すhit()メソッドを記述しています。それが(2)です。プロパティやメソッドの記述方法はクラスと同じです。
メソッド内の処理は「打つ」を模倣したようなものにするために単に「ボールを打ちます」と表示するようにしました。それが(3)です。ただ、そのときに「どのクラスで、このトレイトが利用されたのか」を明確にするように、主語にクラス名を表示させるようにしています。PHPでは実行中のクラス名を表示するための定数が用意されており、(3)の「__CLASS__」が該当します。
さて、同じように「投げる」を表すThrowTraitトレイトを作成しましょう(リスト3)。
<?php trait ThrowTrait { public function throw():void { print(__CLASS__."がボールを投げます。<br>"); } }
基本構造はHitTraitトレイトと同じです。
Copyright © ITmedia, Inc. All Rights Reserved.