このエントリーが役に立ったらシェアをお願いします!

PHP5.4のtrait機能を使ってみる

このエントリーが役に立ったらシェアをお願いします!

今更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
}

その際の対処法として、

  1. 使用する関数を選択
  2. 関数のエイリアスを宣言

をしてやる必要があります。

こちらは片方の関数を選択する方法。

//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って名前付けたのに何も入力させてない。)

以上、トレイトの使用方法でした!

スポンサーリンク

このエントリーが役に立ったらシェアをお願いします!

1この記事を書いた人
ShoheiTai
フロントエンド志向のWebエンジニア。
HTML5やWeb高速化、SEO等のフロントエンド開発が大好物。
バックエンドではCakePHP,Wordpress開発を主戦場としています。
Web開発のスパイスファクトリー株式会社創業メンバー。

イケてないコード - Webエンジニアのブログの
最新情報をいいねしてチェックしよう!