今更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って名前付けたのに何も入力させてない。)
以上、トレイトの使用方法でした!


コメント