PHP5.4から使えるようになったトレイト(trait)を使えば
単一継承だけでは限界のあったコードの再利用が可能になるのでとっても便利です。
**「php 多重継承」**こうググったあなたは是非traitの利用を検討してみましょう。
traitとはメソッドやプロパティーだけをクラスから切り出したもので
クラスはtraitを装備することで「ふるまい」を増やすことが出来ます。
##利用方法
下記はプロパティをJsonで欲しくなったので、クラスではなくトレイトとしてtoJsonメソッドを実装してみた例です。
trait Jsonable
{
public function toJson()
{
return json_encode($this->getAttributes());
}
}
// 親クラス
class Store
{
use Jsonable;
protected $attributes;
public function getAttributes()
{
return $this->attributes;
}
}
// 子クラス
class WebStore extends Store
{
protected $attributes = ['name' => ''];
}
// 子クラス
class RealStore extends Store
{
protected $attributes = ['name' => '', 'address' => ''];
}
Jsonableトレイトを親クラスでuseしていますが、子クラスでuseしたって構いません。
Traitを利用すれば継承関係を汚すこと無く「ふるまい」を増やせるのです。
##前提条件を定める
先程の例に出てきたJsonableトレイトですが、StoreクラスにはgetAttributesメソッドがあるはずと決めつけて書かれています。
もしgetAttributesメソッドが無かった場合は実行時にエラーになっちゃいますね。
下記のようにすればuseした段階でエラーとなってくれるので安心です。
trait Jsonable
{
abstract public function getAttributes(); // 僕を使うならgetAttributesメソッドを実装していること
public function toJson()
{
return json_encode($this->getAttributes());
}
}
これによってトレイトを使うための前提条件を明確に出来るんです。
インターフェースみたいですな。
##基本的なアレコレ
- トレイトはいくつでもuseできるとか
- もしその中に同名メソッドを持つトレイトがいたらとか
- その場合の回避方法だとか
- トレイトが更に別のトレイトをuseできるとか
PHPの公式マニュアルで丁寧に説明されているので一読しておくと良いでしょう。
##命名例
PHPとして命名規則はありません。どんな名前を付けても自由ですがオススメはあります。
オススメといっても僕がわかりやすい!と感じた2つの法則です。
- トレイトをuseすると「〜できる」ようになるので「able」使うと分かりやすい。
- 単純にTraitを付けちゃう。クラスとかと同じディレクトリに置く場合に区別しやすい。
トレイト名 | トレイト名からイメージできる機能 |
---|---|
Jsonable | JSON化出来る |
JsonParserTrait | JSONを解析できる |
Authenticatable | 認証出来る |
Queueable | キューに突っ込めるようになる |
##ユニットテスト
トレイト単体ではインスタンス化する事が出来ません。
そうなると仮のクラスにuseさせてテストしなくてはいけません。激めんどいっすね。
でもPHPUnitのgetMockForTraitメソッドを使えばスマートにテスト出来ます。
getMockForTraitメソッド便利。
https://phpunit.de/manual/current/ja/test-doubles.html#test-doubles.mocking-traits-and-abstract-classes
##テクニックてきな
トレイトはインターフェースのような役割も果たすため、
instanceOfを使って処理を分岐するように、method_existsを使って分岐させてという感じで
フレームワークでしばしそういった処理を見ます。