interfaceは実装を定義する記法です。interfaceはimplementsによって任意の数指定され、classはimplements以下で指定したinterface全ての実装が必須になります。
interface A{ public function hoge(); public function fuga(); } interface B{ public function foo(); public function bar(); } class C implemnts A,B{ public function hoge(){ // Cに関するhoge()の具体的な処理 } public function fuga(){ // Cに関するfuga()の具体的な処理 } public function foo(){ // Cに関するfoo()の具体的な処理 } public function bar(){ // Cに関するbar()の具体的な処理 } } class D implemnts A{ public function hoge(){ // Dに関するhoge()の具体的な処理 } public function fuga(){ // Dに関するfuga()の具体的な処理 } }
PHP: オブジェクト インターフェイス – Manual
interfaceで実装を強要される関数はinterafaceの時点で何かしら達成する目的を持ちます。もし目的を持たないならば、その関数それぞれの中身は乱雑なものになり、インタフェースによってコードの設計を整理することはできないでしょう。
interfaceで定義されたメソッドは実装は異なれど共通の目的を持ちます。そのため、その目的が達成できているか否かのテストが欲しくなります。このテストは同じinterfaceを持つクラスならば共通化できます。traitを用いて共通化を実現します。
traitはコードを再利用するための仕組みです。
PHP: トレイト – Manual
traitの再利用の仕組みの特徴は複数のtraitを一つのclassで使えることです。is-a関係に従わない場合、混乱の元になる継承との最大の違いがこの特徴です。
class TestC extend TestBase{ use TraitHoge,TraitFuga; }
interfaceに関するテストをtraitにまとめることでコードの整理をします。ある一つのinterfaceを実装したクラスをテストするならば、その一つのinterfaceに対応する一つのtraitを呼び出す、という具合です。
trait TestATrait{ function testHoge(){ // hoge()共通のテスト } function testFuga(){ // fuga()共通のテスト } } class TestC extend TestBase{ use TestATrait,TestBTrait; } class TestD extend TestBase{ use TestATrait; }
interfaceの呼ばれ方はクラスによってまちまちであり、それら全てをテストする際、継承や参照を用いると謎のクラスや妙な場所を通るといったことが起きやすいです。テストをコピペをするとコードの変更をテストに反映する際の労力が大きくなります。interfaceとtraitは1対1の関係で作ることが容易であり、セットで用いることによってコードをきれいに保てます。