Wiz テックブログ

Wizは、最新のIoTやICTサービスをお客様に届ける「ITの総合商社」です。

PHPのInterface -メリットと使い所-

今回はPHPのInterfaceの使い所について、例を交えつつ紹介してみようと思います。

本題に入る前にこの記事内のサンプルコードについてです。
サンプルコードは全て、フレームワークにLaravelを使用しているという前提で記述しています。
LaravelでInterfaceを使う場合、サービスプロバイダーのregisterメソッド内でbindメソッドを使用し、実装クラスとInterfaceの紐付けを行ってください。

$this->app->bind(XxxInterface::class, ConcreteClass::class);

これがないと"XxxInterface is not instantiable..."みたいなエラーが出てしまいますので、ご注意ください。

Interfaceの概要

PHPの公式ドキュメントを確認すると、以下のように説明されています。

オブジェクトインターフェイスにより、あるクラスが実装する必要があるメソッドの 種類を、これらのメソッドの実装を定義することなく、指定するコードを作成できる ようになります。

インターフェイスは通常のクラスと同様に定義することができますが、 キーワード class のかわりに interface を用います。またメソッドの実装は全く定義されません。

インターフェイス内で宣言される全てのメソッドはpublicである必要があります。 これは、インターフェイスの特性によります。 https://www.php.net/manual/ja/language.oop5.interfaces.php

Interfaceを使うメリット

"php interface メリット"などのキーワードでググるといろいろ出てきますが、大きなメリットの一つとして

ということがあげられます。
Interfaceを使うと、複数のクラスがお互いに直接依存し合わず、Interfaceに依存している状態を作ることができます。

どういう状態なのか、以下の例1をご覧ください。

例1

  • メルマガを配信するような機能があったとする
  • 外部のメールサービスを使っている
  • メールサービスのAPI呼び出し用にライブラリが提供されており、それを使って機能を実装している

という状態があるとします。
サンプルコードで書いてみると、こういう感じです。

ある時、使用しているメールサービスを変更するような仕様変更があったとします。
その場合、上記のようにInterfaceを使った実装をしていれば、変更の影響範囲をEmailLibServiceのみに抑えることができます。

コントローラーのemailMagazineメソッドでは、EmailLibInterfaceのsendというメソッドを呼び出しています。
EmailLibServiceのsendメソッドを直接使用していません。
なので使用するメールサービスが変わった場合にEmailLibServiceの中身を書き換えようが、新しくクラスを作って差し替えようが、EmailLibInterfaceさえimplementsされていれば呼び出し元に影響が及ぶことはありません。

例えばコントローラーからライブラリのクラスを直接newして使用していたり、あるいはEmailLibServiceのメソッドを直接呼び出していたとすると、コントローラーにも影響が及んでいたかもしれません。

Abstract classでもいいのでは?

Abstract classについてはこちらをご覧ください。

https://www.php.net/manual/ja/language.oop5.abstract.php

InterfaceとAbstract classは

  • 抽象メソッドを定義できる
  • 定義されたメソッドを継承先のクラス(Interfaceは実装クラス)で必ず実装しなければならない
  • そのままでは使えない(直接newしてインスタンスを作成したりできない)

などの点で似ています。しかし

  • Interfaceのメソッドは全てpublicでなければならない
  • Abstract classはInterfaceと違って、メソッドに具体的な実装内容を持たせることができる

などの違いがあります。
なのでAbstract classを使えば共通処理を具体的な実装部分まで定義してしまって、動きが変わる部分のみ抽象メソッドで定義するようなことが可能です。
Abstract classの方ができることが多く自由度が高いので、Interfaceを使う必要がなさそうに思えます。
しかし、具体的な処理を持った共通メソッドに変更を加える必要がある場合、継承先クラス全てに影響が及んでしまうというデメリットがあります。
そう考えるとInterfaceの場合は元々実装内容を持たないので、変更に強いと考えられます。
振る舞いが異なるという前提で同じメソッドを不特定多数のクラスに持たせたい場合は、Interfaceを使用するメリットがあるのではないでしょうか。
ということを踏まえた上で、2つ目の例です。

例2

例えばユーザーに何かしらの通知を送るようなことがあったとして

  • パラメーターによってどういう通知を送信するかを変えたい
  • 通知のフォーマットや通知に必要な要素はバラバラ

みたいな条件を満たして実装したい場合、以下のような使い方ができます。

(参考: https://youtu.be/cUV1nXPfjFY)

Interfaceは複数implementsできる

もう一つAbstract classとInterfaceの特徴的な違いは、Interfaceは複数implementsできるという点です。

https://www.php.net/manual/ja/language.oop5.interfaces.php#language.oop5.interfaces.implements

PHPは多重継承ができない仕様です。Abstract classを使用する場合、あくまでもクラスの継承なので1つのAbstract classしか継承できません。対してInterfaceに個数の縛りはありません。カンマ区切りで複数implementsが可能です。

例えば例2で "ある通知クラスの場合は管理者にも同時に通知を送りたい" みたいな場合、以下のような形で複数implementsすると便利なのではないでしょうか。

↑のように空のInterfaceを作成して、自作の型のように手軽に扱えるのもInterfaceのいいところだと思います。

さいごに

Wizではエンジニアを募集しております。 興味のある方、ぜひご覧下さい。

【フロントエンドエンジニア】 場所にとらわれず自社メディア成長に貢献したいフロントエンドエンジニア募集! - 株式会社WizのWebエンジニアの求人 - Wantedly

【バックエンドエンジニア】 勤務地自宅を叶える!バックエンドエンジニアとして事業を成長させたい方募集 - 株式会社WizのWebエンジニアの求人 - Wantedly