PHP
 Computer >> コンピューター >  >> プログラミング >> PHP

PHPのトレイト(Trait)とは?コード再利用の仕組みと使い方を実例付きで解説

はじめに

PHPは多重継承をサポートしていません。この制限をある程度補ってくれるのがトレイト(trait)という機能です。トレイトはコードの再利用を目的とした仕組みであり、その定義方法はクラスによく似ています。ただし、トレイトは直接インスタンス化することができません。代わりに、useキーワードを使うことで、クラスの中にトレイトの機能を取り込むことができます。

トレイトを取り込んだクラスは、その中で定義されたメソッドをそのまま使うこともできますし、必要に応じてオーバーライドすることも可能です。さらに重要なのは、トレイトは通常の親クラスからの継承と併用できるという点です。これにより、実質的に多重継承のような効果を実現できます。

また、トレイトはインターフェースにも似ています。両者の違いは次のとおりです。インターフェースはメソッドの実装を含まず、その実装はimplementsしたクラス側で必ず行わなければなりません。一方、トレイトはメソッド本体を持つことができ、それを使うクラス側ではオーバーライドしてもしなくても構いません。

基本構文

<?php
trait testtrait{
   public function test1(){
      // メソッドの処理内容
   }
}
// トレイトを使用する
class testclass{
   use testtrait;
   // クラスのその他のメンバー
}
?>

例:トレイト内のメソッドをオーバーライドする

次のコードでは、2つのメソッドを持つトレイトをクラスで使用し、そのうちの1つのメソッドをオーバーライドしています。

<?php
// トレイトの定義
trait testtrait{
   public function test1(){
      echo "test1 method in trait\n";
   }
   public function test2(){
      echo "test2 method in trait\n";
   }
}
// トレイトを使用する
class testclass{
   use testtrait;
   public function test1(){
      echo "test1 method overridden\n";
   }
}
$obj=new testclass();
$obj->test1();
$obj->test2();
?>

出力結果

実行すると、以下のように出力されます。

test1 method overridden
test2 method in trait

test1()はクラス側でオーバーライドされたため上書き版が出力され、test2()はトレイト本来の実装がそのまま使われていることが分かります。

子クラスでのトレイト使用 ― 多重継承的な効果

ここがトレイト最大の利点です。親クラスを持つクラスでもトレイトを使用でき、さらにそのメソッドをオーバーライドすることもできます。つまり、単一継承しか許さないPHPでも、複数のソースから機能を受け継ぐような設計が可能になります。

<?php
// トレイトの定義
trait testtrait{
   public function test1(){
      echo "test1 method in trait\n";
   }
}
// 親クラス
class parentclass{
   public function test2(){
      echo "test2 method in parent\n";
   }
}
// トレイトと親クラスを併用する
class childclass extends parentclass{
   use testtrait;
   public function test1(){
      echo "parent method overridden\n";
   }
   public function test2(){
      echo "trait method overridden\n";
   }
}
$obj=new childclass();
$obj->test1();
$obj->test2();
?>

出力結果

上記のコードを実行すると、以下の結果が得られます。

parent method overridden
trait method overridden

このように、トレイト由来のメソッドも親クラス由来のメソッドも、子クラス側で自由にオーバーライドできます。

インターフェースとの併用

1つのクラスで、インターフェースの実装・他クラスの継承・トレイトの使用を同時に行うこともできます。

<?php
// トレイトの定義
trait mytrait{
   public function test1(){
      echo "test1 method in trait1\n";
   }
}
class myclass{
   public function test2(){
      echo "test2 method in parent class\n";
   }
}
interface myinterface{
   public function test3();
}
// トレイト・親クラス・インターフェースを併用する
class testclass extends myclass implements myinterface{
   use mytrait;
   public function test3(){
      echo "implementation of test3 method\n";
   }
}
$obj=new testclass();
$obj->test1();
$obj->test2();
$obj->test3();
?>

出力結果

このスクリプトは以下の出力を生成します。

test1 method in trait1
test2 method in parent class
implementation of test3 method

メソッド名の衝突の解決

1つのクラスが同じメソッド名を持つ2つのトレイトを使用した場合、衝突が発生します。この問題は、スコープ解決演算子(::)とinsteadofキーワードを組み合わせて解決します。

<?php
trait trait1{
   public function test1(){
      echo "test1 method in trait1\n";
   }
   public function test2(){
      echo "test2 method in trait1\n";
   }
}
trait trait2{
   public function test1(){
      echo "test1 method in trait2\n";
   }
   public function test2(){
      echo "test2 method in trait2\n";
   }
}
// 2つのトレイトを併用し、衝突を解決する
class testclass {
   use trait1, trait2{
      trait1::test1 insteadof trait2;
      trait2::test2 insteadof trait1;
   }
}
$obj=new testclass();
$obj->test1();
$obj->test2();
?>

出力結果

上記のスクリプトは以下の結果を出力します。

test1 method in trait1
test2 method in trait2

この例では、test1()にはtrait1の実装が、test2()にはtrait2の実装が採用されます。
なお、asキーワードを使えば、衝突しているメソッドの一方に別名を付けて両方を利用することも可能です。トレイトを活用すれば、継承に頼りすぎない柔軟で再利用性の高いコード設計が実現できます。

  1. PHPのpi()関数とは?使い方と定義済み定数との対応を実例付きで解説

    pi()関数の定義と使い方PHPのpi()関数は、数学定数π(円周率)の値を返す関数です。戻り値はfloat型の「3.14159265359」であり、PHPにあらかじめ定義されている定数M_PIとまったく同じ値になります。構文pi ( void ) : floatパラメータこの関数は引数を受け取りません。引数なしでそのまま呼び出すことができます。戻り値pi()関数は数学定数πの値を返し、定義済みの数学定数M_PIと等価です。数式の中では、M_PIの代わりにpi()関数を使うこともできます。対応するPHPバージョンこの関数はPHP 4.x、PHP 5.x、PHP 7.xのすべてのバージョンで利用

  2. PHPのトレイト(trait)とは?特徴と基本的な使い方を解説

    PHP 5.4から、オブジェクト指向プログラミングに「トレイト(trait)」という機能が導入されました。トレイトはクラスによく似た仕組みですが、その役割はメソッド群をきめ細かく、かつ信頼性の高い形でグループ化することに特化しています。トレイトは単体でインスタンス化することはできません。PHPにトレイトが導入された最大の目的は、単一継承の問題を解決することです。PHPでは、クラスは1つの親クラスからしか継承できないため、複数のクラスにまたがる機能の再利用が難しいという課題がありました。トレイトを使えば、異なるクラス階層に属する複数の独立したクラス間で、メソッドのセットを自由に再利用できるように