今更5.4?って言われてしまうかもしれませんが、
今回は便利そうなtraitについて紹介していきます。
traitに関数を切り出す事で様々なクラスで利用でき、拡張性を高めることができます。
僕はtraitを最近知りました(小声
これを使うと設計方法も多少変わるのではないでしょうか。
traitとは
PHP5.4から追加されたもので、モジュールをクラスとは別にまとめて管理することができます。
変数や関数をtraitに作成し、他のクラスで使い回して利用するという感じです。
PHPの単一継承を和らげるという効果があります。
traitの仕組み自体はクラスと似ていますが、インスタンスにできないという点が大きく異なります。
traitの使い方
/** * Outputトレイトの作成 */ trait Output { public $str = 'hello '; public function echoTrait() { echo 'trait!'; } }
classの代わりにtraitと書きます。
そして後はクラスと同じように関数を書くもよし、変数を定義するもよし。
クラスを作る感覚で作成して構いません。
そしてtraitを使用するときはクラス内でuse宣言を行います。
useで宣言することで、traitの内容がクラスでも利用することができます。
/** * traitの作成 */ trait Output { public $str = 'hello '; public function echoTrait() { echo 'trait!'; } } class Test { //使うtraitを宣言する use Output; } //Testインスタンスを作成し、Testクラスからtraitを利用する。 $test = new Test(); //変数の呼び出し echo $test->str; //hello //関数の呼び出し $test->echoTrait(); //trait!
このように、Testクラスの変数・関数として、traitの中身を使用することができます。
単一継承の壁を超える
先ほどの使い方を見ると、なんとなく分かると思いますが、
traitはクラスを継承した時と全く同じ動きをします。
なのでtraitを使用したクラスを継承し、traitの持つ関数をオーバーライドすることも可能です。
trait Output { public $str = 'hello '; public function echoTrait() { echo 'trait!'; } } class Test { //使うtraitを宣言する use Output; } class Practice extends Test { //traitのechoTrait関数をオーバーライドする public function echoTrait() { echo 'trait override!'; } } $prac = new Practice(); //変数の呼び出し echo $prac->str; //hello //関数の呼び出し $prac->echoTrait(); //trait override!
また、trait内でtraitを宣言することもできます。
//Outputトレイト trait Output { public $str = 'hello '; public function echoTrait() { echo 'trait!'; } } //Mathトレイト trait Math { public function add($num1, $num2) { return $num1 + $num2; } } //OutputとMathを組み合わせたトレイト trait MathOutput { use Output, Math; } class Test { //使うtraitを宣言する use MathOutput; } $test = new Test(); $test->echoTrait(); //trait!! echo $test->add(2, 3); //5
こんな形でtraitをカスタマイズしていくことができます。
そしてなんと、trait内の関数にabstractを付けて抽象化をすることもできます。
trait Output { //抽象関数 abstract function echoTrait(); } class Test { use Output; //traitの抽象関数を実装 function echoTrait() { echo 'trait!'; } } $test = new Test(); $test->echoTrait(); //trait!
traitの注意点
もし、複数のトレイトを使用した際に関数名が被るとエラーになってしまいます。
//Outputトレイト trait Output { function A() { echo 'Output!'; } } //Inputトレイト trait Input { function A() { echo 'Input!'; } } //名前の衝突が起こってしまったクラス class Test { use Output,Input; //FatalError }
その際の対処法として、
- 使用する関数を選択
- 関数のエイリアスを宣言
をしてやる必要があります。
こちらは片方の関数を選択する方法。
//Outputトレイト trait Output { function A() { echo 'Output!'; } } //Inputトレイト trait Input { function A() { echo 'Input!'; } } //名前の衝突が起こってしまったクラス class Test { use Output,Input { //InputのAじゃなくてOutputのA使います宣言 Output::A insteadof Input; } } $test = new Test(); $test->A(); //Output!
こちらは両方の関数を共存させる方法。
//Outputトレイト trait Output { function A() { echo 'Output!'; } } //Inputトレイト trait Input { function A() { echo 'Input!'; } } //名前の衝突が起こってしまったクラス class Test { use Output,Input { //InputのAじゃなくてOutputのA使います宣言 Output::A insteadof Input; //あ、ちなみにInputのAはBという名前になります宣言 Input::A as B; } } $test = new Test(); $test->A(); //Output! $test->B(); //Input!
insteadofが少し分かりづらいというのもあるので
名前の衝突は極力起こらないような設計がいいですね。
(後から気づいたけど、Inputって名前付けたのに何も入力させてない。)
以上、トレイトの使用方法でした!
コメント