[PHP] トレイト

もくじ
記事内に商品のプロモーションを含む場合があります。
PHPのトレイトについてのメモです。 ここでは基本のコードと、継承時メンバー名が重複した時の挙動を確認してみました。
基本コード
トレイトのコード コードを開く
1<?php
2
3trait SayHello
4{
5 function sayHello() {
6 echo "say hello.", "\n";
7 }
8}
9
10class Person
11{
12 use SayHello; // 上で定義したトレイトの名前
13
14 function say()
15 {
16 echo "say.", "\n";
17 }
18}
19$person = new Person();
20$person->say();
21$person->sayHello(); // トレイトのメソッド
- 5.4.0以降で使える。
- 単一継承でできないようなコードの再利用ができるようになる。
- トレイトからインスタンスの生成はできない
継承とトレイトを使ってみる
ここでは継承したクラスにトレイトを追加するサンプルを作ってみます。
Actorは攻撃手段を持っていて、継承してHeroになると回復手段を持ち、トレイトで攻撃魔法を追加する、みたいな感じのコード。
コード
コードを開く
1<?php
2
3trait SkillFire
4{
5 function fire()
6 {
7 echo "skill fire.", "\n";
8 }
9}
10
11class Actor
12{
13 function attack()
14 {
15 echo "attack.", "\n";
16 }
17}
18
19class Hero extends Actor
20{
21 use SkillFire;
22
23 function cure()
24 {
25 echo "skill cure.", "\n";
26 }
27}
28
29$person = new Hero();
30$person->attack(); // Actorのattackメソッド
31$person->cure(); // Heroのcureメソッド
32$person->fire(); // SkillFire(トレイト)のメソッド
結果
1attack.
2skill cure.
3skill fire.
メンバーの優先順位(同じ名前がカブった時)
トレイトを追加したクラス・親クラスに同じメンバがあった場合はどうなるか?
つまりみんなが同じメソッドとか持っていた場合は、どれが優先されるのか?という場合の話です。
優先順位は以下のようになっています。
| 優先度 | 優先されるメンバ |
|---|---|
| 1番目(最優先) | トレイトを使うクラス |
| 2番目 | トレイト |
| 3番目 | 継承するクラス |
優先度が1番目を試す(クラスのメンバ)
親クラス・サブクラス・トレイトで同じメソッドを定義して1番目(トレイトを使うクラス)が優先されることを確認します。
ここではMagicianクラスのfireが優先して呼び出されることをコードで確認していきます。
サンプル コードを開く
1// トレイト
2trait SkillFire
3{
4 function fire()
5 {
6 echo "skill fire.", "\n";
7 }
8}
9
10// 親クラス
11class Actor
12{
13 function fire()
14 {
15 echo "actor fire.", "\n";
16 }
17}
18
19// 子クラス
20class Magician extends Actor
21{
22 use SkillFire;
23
24 function fire()
25 {
26 echo "magician fire", "\n";
27 }
28}
29
30$magician = new Magician();
31$magician->fire();
結果は以下のようになります。 Magicianクラスが持つfireメソッドが呼び出されていますね。
1magician fire
優先度が2番目を試す(トレイト)
親クラス・サブクラス・トレイトで同じメソッドを定義して2番目(トレイト)が優先されることを確認します。
今回はMagicialクラスはfireメソッドを持っておらず、Actorとトレイトがfireメソッドを持っています。
このケースではトレイトのfireメソッドが優先されることを確認していきます。
サンプル コードを開く
1<?php
2
3// トレイト
4trait SkillFire
5{
6 function fire()
7 {
8 echo "skill fire.", "\n";
9 }
10}
11
12// 親クラス
13class Actor
14{
15 function fire()
16 {
17 echo "actor fire.", "\n";
18 }
19}
20
21// 子クラス
22class Magician extends Actor
23{
24 use SkillFire;
25
26 // マジシャンですがまだスキルを持っていません!
27}
28
29$magician = new Magician();
30$magician->fire();
結果は以下の通りになります。
1skill fire.
トレイトクラスのfireメソッドが呼ばれているので、優先度2(トレイト)であることが確認できました。
優先度が3番目を試す(継承したクラス)は省略
これはトレイトのメンバ名とクラスのメンバ名が異なっているので、衝突が起こっていない状態です。
この場合は継承されたメンバが優先されるので、サンプルは省略します。

