PHPのインターフェイスのポイントは何ですか?


224

インターフェイスを使用すると、それを実装するクラスのメソッドを定義するコードを作成できます。ただし、これらのメソッドにコードを追加することはできません。

抽象クラスを使用すると、メソッドにコードを追加するだけでなく、同じことを実行できます。

抽象クラスで同じ目標を達成できるとしたら、なぜインターフェイスの概念さえ必要なのでしょうか。

私はそれがC ++からJavaへのOO理論に関係していると言われています。これは、PHPのOOの基礎となっているものです。この概念はJavaでは有用ですが、PHPでは有用ではありませんか?これは、抽象クラスでプレースホルダがポイ捨てされないようにするための単なる方法ですか?何か不足していますか?


4
これを読む必要があります:stackoverflow.com/a/384067/14673
Luc M

それは精神的な助けであり、コミュニケーションの助けであることを確信してください。インターフェースは、実装について知らなくても読み取ることができる抽象的な方法でAPIが公開するサービスをまとめるため、APIの優れた教育ツールとして機能します。これは高価ですが、インターフェースに慣れている人は、クラスを必要とせずに関数を直接使用できるため、ポインタを節約できます。言語で定義されたインターフェースがないと、多くのプログラマーのために前もって計画を立てるのは難しいかもしれません。
ドミトリー

回答:


142

インターフェースの重要な点は、クラスに複数のインターフェースを実装するように強制する柔軟性を与えることですが、それでも多重継承は許可しません。複数のクラスからの継承に関する問題は数多くあり、さまざまであり、ウィキペディアのページにそれらがまとめられています。

インターフェイスは妥協です。多重継承の問題のほとんどは抽象基本クラスには当てはまらないため、最近のほとんどの言語では多重継承を無効にし、抽象基本クラスインターフェースを呼び出し、クラスがそれらの多くを「実装」できるようにします。


39
*インターフェースは実装がゼロのクラスの設計を提供するとも言えます。*抽象クラスは、設計と実装を提供します。抽象クラスは、子クラスが実装の類似点を共有しているが、特定の実装では異なる場合に最も役立ちます。
Jrgns 2012

@Craig、多重継承に固有の問題はありません。現在の言語はそれらを適切に実装するのに十分強力ではないということだけです。「問題」は実際にはかなり簡単に修正できます。たとえば、同じ名前の継承された関数の継承の明示的なパスを指定すると、ダイヤモンドのジレンマを解決できる場合があります。
Pacerier 2015年

15
それは、インターフェイスの目的ではありません。これは多重継承に対する妥協ではなく、オブジェクトを実装し、他のオブジェクト/メソッドが消費するための概念的で抽象的なコントラクトを作成することです。インターフェースは、ポリモーフィズムのためのツールであり、直接継承のためのものではありません。
マダラのゴースト

123

この概念は、オブジェクト指向プログラミングのあらゆる場面で役立ちます。私にとってインターフェースは契約だと思います。私のクラスとあなたのクラスがこのメソッド署名契約に同意する限り、私たちは「インターフェース」することができます。抽象クラスについては、いくつかのメソッドをスタブ化する基本クラスとして多く見ているため、詳細を入力する必要があります。


これで少しわかりました。これは名前空間の場合と同じです。したがって、共有コードは使いやすく、競合はありません。2人が同じベースでクラスを作成する方が簡単ですよね?
RedClover 2017

「インターフェース」の一般的な概念を、PHPのような言語の具体的なインターフェースと区別する必要はありませんか?たとえば、どの関数にも、その使用方法を定義し、その実装を隠す「インターフェース」があります。そのため、この種の「契約」インターフェイスには、特別な言語機能は必要ありません。したがって、言語機能は何か他のもの(又はそれに加えて何か)のためでなければならない、。
UuDdLrLrSs

70

抽象クラスがすでにあるのに、なぜインターフェースが必要なのでしょうか? 多重継承を防ぐため(複数の既知の問題を引き起こす可能性があります)。

そのような問題の1つ:

「ダイヤモンドの問題」(「致命的な死のダイヤモンド」と呼ばれることもあります)は、2つのクラスBとCがAから継承し、クラスDがBとCの両方から継承する場合に発生する曖昧さです。Aにメソッドがある場合、 BとCはオーバーライドされ、Dはオーバーライドしません。Dが継承するメソッドのバージョンは、Bのバージョンですか、それともCのバージョンですか。

出典:https : //en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem

なぜ/いつインターフェースを使用するのですか? 例...世界のすべての車は同じインターフェース(メソッド)を持っています... AccelerationPedalIsOnTheRight()BrakePedalISOnTheLeft()。各自動車ブランドがこれらの「方法」を他のブランドとは異なるものにすると想像してください。BMWは右側にブレーキがあり、ホンダはホイールの左側にブレーキがあります。人々は、異なるブランドの車を購入するたびに、これらの「方法」がどのように機能するかを学ぶ必要があります。そのため、同じインターフェースを複数の「場所」に配置することをお勧めします。

インターフェイスはあなたのために何をしますか(なぜ誰かがそれを使うのですか?)インターフェースは、「ミス」を防ぐことができます(特定のインターフェースを実装するすべてのクラスが、すべてインターフェースにあるメソッドを持つことを保証します)。

// Methods inside this interface must be implemented in all classes which implement this interface.
interface IPersonService
{   
    public function Create($personObject);
}

class MySqlPerson implements IPersonService
{
    public function Create($personObject)
    {
        // Create a new person in MySql database.
    }
}

class MongoPerson implements IPersonService
{
    public function Create($personObject)
    {
        // Mongo database creates a new person differently then MySQL does. But the code outside of this method doesn't care how a person will be added to the database, all it has to know is that the method Create() has 1 parameter (the person object).
    }
}

このように、Create()メソッドは常に同じ方法で使用されます。MySqlPersonクラスを使用するか、MongoPersonクラスを使用するかは関係ありません。メソッドの使用方法は変わりません(インターフェースは変わりません)。

たとえば、次のように使用されます(コードのすべての場所)。

new MySqlPerson()->Create($personObject);
new MongoPerson()->Create($personObject);

このように、このようなことは起こりえません:

new MySqlPerson()->Create($personObject)
new MongoPerson()->Create($personsName, $personsAge);

複数の異なるインターフェースよりも、1つのインターフェースを覚えてどこでも同じインターフェースを使用する方がはるかに簡単です。

このように、Create()メソッドの内部は、このメソッドを呼び出す「外部」コードに影響を与えることなく、クラスごとに異なる場合があります。外部コードが知っている必要があるのは、メソッドCreate()が1つのパラメーター($personObject)を持っていることだけです。これは、外部コードがメソッドを使用/呼び出す方法だからです。外部コードは、メソッド内で何が起こっているかを気にしません。それを使用/呼び出す方法を知っていればよいだけです。

インターフェースがなくてもこれを行うことができますが、インターフェースを使用する場合は「安全」です(間違いを防ぐため)。インターフェイスは、メソッドCreate()がインターフェイスを実装するすべてのクラスで同じシグネチャ(同じ型と同じ数のパラメーター)を持つことを保証します。このようにして、IPersonServiceインターフェースを実装するすべてのクラスが確実にメソッドを持ちCreate()(この例では)、$personObject呼び出し/使用するために必要なパラメーター()は1つだけです。

インターフェースを実装するクラスは、インターフェースが行う/持つすべてのメソッドを実装する必要があります。

何度も繰り返さなかったといいのですが。


車のペダルとの本当にいいアナロジー!
James

24

インターフェイスの使用と抽象クラスの使用の違いは、言語自体による強制よりも、コードの編成に関係しています。他の開発者が意図した設計パターン内に収まるように作業するためのコードを準備するとき、私はそれらを頻繁に使用します。インターフェイスは一種の「契約による設計」であり、これにより、コードは、アクセス権のないコードから送信される可能性のある所定のAPI呼び出しのセットに応答することに同意します。

抽象クラスからの継承は「is a」関係ですが、それが常に望んでいることではありません。また、インターフェースの実装は、「aのような」関係のようなものです。この違いは、特定の状況では非常に重要です。

たとえば、抽象クラスAccountがあり、そこから他の多くのクラス(アカウントのタイプなど)が拡張されているとします。そのタイプのグループにのみ適用できる特定のメソッドセットがあります。ただし、これらのアカウントサブクラスの一部は、Versionable、Listable、またはEditableを実装しているため、これらのAPIの使用を想定しているコントローラーに投入できます。コントローラは、それがどのタイプのオブジェクトであるかを気にしません

対照的に、Accountから拡張しないオブジェクトを作成することもできます(User抽象クラスなど)。ListableおよびEditableを実装しますが、Versionableは実装しません。これは、ここでは意味がありません。

このように、FooUserサブクラスはアカウントではありませんが、編集可能オブジェクトのように機能します。同様に、BarAccountはAccountから拡張されていますが、Userサブクラスではありませんが、Editable、Listable、Versionableを実装しています。

Editable、Listable、VersionableのこれらすべてのAPIを抽象クラス自体に追加すると、乱雑で見苦しいだけでなく、AccountとUserの共通インターフェイスを複製するか、UserオブジェクトにVersionableの実装を強制し、おそらく単に例外。


これはここです。開発者にメソッドを拡張または上書きせずに使用するよう厳密に強制する
Nick

21

インターフェイスは基本的に、作成できるものの青写真です。これらはクラスが持つ必要のあるメソッドを定義しますが、それらの制限の外に追加のメソッドを作成できます。

メソッドにコードを追加できないことで何を意味するのかわかりません。抽象クラスまたはそれを拡張するクラスにインターフェイスを適用していますか?

抽象クラスに適用されるインターフェースのメソッドは、その抽象クラスに実装する必要があります。ただし、そのインターフェースを拡張クラスに適用すると、メソッドは拡張クラスに実装するだけで済みます。私はここで間違っている可能性があります-できる限り/頻繁にインターフェイスを使用しません。

私は常に、インターフェースを外部の開発者のためのパターン、または物事が正しいことを確認するための追加のルールセットとして考えてきました。


9
PHPでは、インターフェースにはメソッド宣言のみが含まれ、実際の実装は含まれません。ただし、抽象クラスを使用すると、メソッドに「コードを追加」して、それを拡張するクラスに継承させることができます。この違いは、mkが言っていたものだと思います。
nocash 2009年

13

PHPではインターフェースを使用します。

  1. 実装を隠す-オブジェクトのクラスへのアクセスプロトコルを確立し、そのオブジェクトを使用したすべての場所でリファクタリングを行わずに、基礎となる実装を変更します。
  2. タイプを確認するには-パラメータに特定のタイプがあることを確認する場合と同様 $object instanceof MyInterface
  3. 実行時にパラメータチェックを実行するには
  4. 複数の動作を単一のクラスに実装するには(複合型を構築する)

    クラスCarはEngineInterface、BodyInterface、SteeringInterface {

その結果、Carオブジェクトは現在、CA start()stop()(EngineInterface)又はgoRight()goLeft()(ステアリングインターフェース)

そして今は考えられないこと

番号4は、抽象クラスでは対応できない最も明白なユースケースでしょう。

Javaで考えることから:

インターフェイスは、「これは、この特定のインターフェイスを実装するすべてのクラスがどのようになるかを示しています。」と述べています。したがって、特定のインターフェイスを使用するコードは、そのインターフェイスに対して呼び出すことができるメソッドを認識しており、それがすべてです。したがって、インターフェイスはクラス間の「プロトコル」を確立するために使用されます。


10

インターフェースは、クラスが拡張できるベースとしてではなく、必要な関数のマップとして存在します。

以下は、抽象クラスが適合しないインターフェースの使用例です
。ユーザーが外部ソースからカレンダーデータをインポートできるカレンダーアプリケーションがあるとします。データソースの各タイプ(ical、rss、atom、json)のインポートを処理するクラスを作成します。これらの各クラスは、アプリケーションがデータを取得するために必要な共通のパブリックメソッドをすべて確実に持つ共通のインターフェイスを実装します。

<?php

interface ImportableFeed 
{
    public function getEvents();
}

次に、ユーザーが新しいフィードを追加すると、フィードのタイプを識別し、そのタイプ用に開発されたクラスを使用してデータをインポートできます。特定のフィードのデータをインポートするために作成された各クラスは、完全に異なるコードを持っています。そうでない場合、アプリケーションがそれらを使用できるようにするインターフェースを実装する必要があるという事実を除いて、クラス間の類似点はほとんどありません。抽象クラスを使用する場合、getEvents()メソッドをオーバーライドしていないため、このインスタンスでアプリケーションが壊れるという事実を非常に簡単に無視できますが、インターフェイスを使用すると、いずれかのメソッドが存在する場合にアプリを実行できませんインターフェースで定義されたものが、それを実装したクラスに存在しません。私のアプリは、フィードからデータを取得するためにどのクラスを使用するかを気にする必要はありません。

これをさらに一歩進めるために、別のフィードタイプを追加するつもりでカレンダーアプリに戻ったときに、インターフェースが非常に役立つことがわかりました。ImportableFeedインターフェースを使用すると、このインターフェースを実装する新しいクラスを追加するだけで、さまざまなフィードタイプをインポートするクラスを追加し続けることができます。新しいフィードインポートクラスがImportableFeedインターフェースを実装している限り、コアアプリケーションはインターフェースが必要とする利用可能なパブリックメソッドにのみ依存しているため、コアアプリケーションに不必要に大量を追加することなく、大量の機能を追加できます。私はそれを所定の位置に落として、動き続けることができることを知っています。

これは非常に単純なスタートです。次に、クラスが処理するフィードタイプに固有のより多くの機能を提供する、すべてのカレンダークラスの実装に必要な別のインターフェイスを作成できます。もう1つの良い例は、フィードタイプなどを確認する方法です。

これは問題を超えていますが、上記の例を使用したため、この方法で使用した場合、インターフェースには独自の問題があります。インターフェイスに一致するように実装されたメソッドから返される出力を確認し、これを実現するために、PHPDocブロックを読み取るIDEを使用して、インターフェイスのPHPDocブロックに戻り値の型を型ヒントとして追加する必要があることに気づきました。それを実装する具象クラスに変換します。このインターフェイスを実装するクラスからのデータ出力を使用する私のクラスは、少なくとも、この例で返される配列を予期していることを知っています。

<?php
interface ImportableFeed 
{
    /**
     * @return array
     */
    public function getEvents();
}

抽象クラスとインターフェースを比較する余地はあまりありません。インターフェースは、実装時にクラスに一連のパブリックインターフェースを必要とする単なるマップです。


良い説明:)ありがとう!
Razvan.432 2015

情報を追加するだけ:抽象クラスでは、メソッドを抽象として宣言すると、インターフェースのように動作するため、getEvents()をオーバーライドしなかったという事実を無視できません。アプリは、インターフェイスの場合と同じように失敗します。
Rikudou_Sennin 2017

8

インターフェイスは、開発者が特定のメソッドを確実に実装するためのものではありません。これらのクラスには特定のメソッドがあることが保証されているため、クラスの実際の型がわからなくても、これらのメソッドを使用できます。例:

interface Readable {
  String read();
}

List<Readable> readables; // dunno what these actually are, but we know they have read();
for(Readable reader : readables)
  System.out.println(reader.read());

多くの場合、基本クラスを提供することは、抽象クラスであってもなくても意味がありません。実装が大幅に異なり、いくつかのメソッド以外に共通点を共有していないためです。

動的に型付けされた言語には、インターフェイスを必要としない「ダックタイピング」の概念があります。オブジェクトには、呼び出すオブジェクトのメソッドがあると自由に想定できます。これは、オブジェクトにメソッド(私の例ではread())がある静的型付け言語の問題を回避しますが、インターフェースを実装していません。


6

私の意見では、インターフェースは非機能的な抽象クラスよりも優先されるべきです。2つのオブジェクトを解析して結合するのではなく、インスタンス化されたオブジェクトが1つしかないため、パフォーマンスに影響があっても驚くことではありません(ただし、確信が持てませんが、内部の仕組みに精通していませんOOP PHPの)。

インターフェースは、たとえばJavaに比べて有用性や意味がありません。一方、PHP6は、戻り値の型ヒントを含む、さらに多くの型ヒントを導入します。これにより、PHPインターフェイスにいくつかの値が追加されます。

tl; dr:インターフェースは、従う必要があるメソッドのリストを定義します(APIと考えてください)。一方、抽象クラスは、サブクラスが特定のニーズに合わせて調整する基本的/共通の機能を提供します。


PHP 6はリリースされません。PHP 6は、2005年から2010年にかけて開発中であったプロジェクトでしたが、延期され、最終的にはキャンセルされました。PHP 7は次のバージョンで、主に以前のPHP 6プロジェクトとの混乱を避けるためです。
Ashu Jha 2016

5

この点でPHPが異なるかどうかは思い出せませんが、Javaでは複数のインターフェースを実装できますが、複数の抽象クラスを継承することはできません。PHPも同じように動作すると思います。

PHPでは、複数のインターフェイスをコンマで区切って適用できます(私は、それがきれいな解決策ではないと思います)。

複数の抽象クラスについては、互いに拡張する複数の抽象クラスを使用することができます(これについても完全にはわかりませんが、以前にどこかで見たことがあると思います)。拡張できない唯一のことは、最終クラスです。


4

インターフェイスは、コードにパフォーマンスの向上などをもたらすことはありませんが、保守しやすくするために大いに役立ちます。抽象クラス(または非抽象クラス)を使用してコードへのインターフェイスを確立できることは事実ですが、適切なインターフェイス(キーワードで定義し、メソッドシグネチャのみを含むインターフェイス)は、並べ替えて読んでください。

そうは言っても、クラスでインターフェースを使用するかどうかを決定するときは、私は裁量を使用する傾向があります。デフォルトのメソッド実装、またはすべてのサブクラスに共通の変数が必要になる場合があります。

もちろん、複数のインターフェースの実装に関するポイントも健全なものです。複数のインターフェースを実装するクラスがある場合、そのクラスのオブジェクトを同じアプリケーションの異なる型として使用できます。

しかし、あなたの質問がPHPに関するものであるという事実は、物事をもう少し面白くします。インターフェースへの入力は、PHPで信じられないほど必要なものではありません。PHPは、そのタイプに関係なく、あらゆるメソッドにほとんど何でもフィードできます。メソッドのパラメーターを静的に入力することはできますが、その一部は壊れています(文字列は問題があると思います)。これを他のほとんどの参照を入力できないという事実と組み合わせると、PHPで静的型付けを強制しようとしても(現時点では)あまり価値がありません。そのため、PHPのインターフェースの価値は、この時点でより強く型付けされた言語よりもはるかに少ないです。読みやすさという利点がありますが、それ以外はほとんどありません。メソッドを宣言し、それらをインプリメンター内で本体に提供する必要があるため、複数の実装は有益ではありません。


2

以下は、PHPインターフェイスのポイントです。

  1. これは、クラスで必要なnoメソッドを定義するために使用されます[htmlをロードする場合は、idとnameが必要なので、この場合、インターフェイスにはsetIDとsetNameが含まれます]。
  2. インターフェイスは、クラスに定義されているすべてのメソッドを含めることを厳密に強制します。
  3. メソッドは、パブリックアクセシビリティとのインターフェイスでのみ定義できます。
  4. クラスのようにインターフェースを拡張することもできます。extendsキーワードを使用して、phpのインターフェイスを拡張できます。
  5. 複数のインターフェースを拡張します。
  6. 両方が同じ名前の機能を共有する場合、2つのインターフェースを実装することはできません。エラーが発生します。

コード例:

interface test{
    public function A($i);
    public function B($j = 20);
}

class xyz implements test{
    public function A($a){
        echo "CLASS A Value is ".$a;
    }
    public function B($b){
        echo "CLASS B Value is ".$b;
    }
}
$x = new xyz();
echo $x->A(11);
echo "<br/>";
echo $x->B(10);

2

抽象クラスとインターフェイスは、子クラスに実装する必要がある抽象メソッドを提供するという点で似ています。ただし、次のような違いがあります。

1.インターフェイスには抽象的なメソッドと定数を含めることができますが、具体的なメソッドと変数を含めることはできません。

2.インターフェイスのすべてのメソッドはパブリックにある必要があります可視性スコープ内。

3.クラスは複数のインターフェースを実装できますが、1つの抽象クラスからのみ継承できます。

                                  interface                      abstract class
the code                     - abstract methods               - abstract methods
                             - constants                      - constants                  
                                                              - concrete methods
                                                              - concrete variables

access modifiers             
                             - public                         - public
                                                              - protected
                                                              - private
                                                                etc.
number of parents          The same class can implement
                           more than 1 interface              The child class can 
                                                              inherit only from 1 abstract class

これが誰でも理解するのに役立つことを願っています!


2

インターフェイスは遺伝子のようなものです。

抽象クラスは実際の親のようなものです。

それらの目的は遺伝的ですが、抽象クラスとインターフェイスの場合、継承されるものはより具体的です。


2

他の言語についてはわかりません。そこでのインターフェースのコンセプトは何ですか。しかし、PHPについては、説明するために最善を尽くします。しばらくお待ちください。これで問題が解決した場合はコメントしてください。

インターフェースは「コントラクト」として機能し、サブクラスのセットが何を行うかを指定しますが、その方法は指定しません。

ルール

  1. インターフェイスはインスタンス化できません。

  2. インターフェイスにメソッドを実装することはできません。つまり、メソッドの.signatureのみが含まれ、details(body)は含まれません。

  3. インターフェースにはメソッドや定数を含めることができますが、属性は含めることができません。インターフェイス定数には、クラス定数と同じ制限があります。インターフェイスメソッドは暗黙的に抽象的です。

  4. インターフェースはコンストラクターまたはデストラクターを宣言してはなりません。これらはクラスレベルの実装の詳細であるためです。

  5. インターフェースのすべてのメソッドは、公開されている必要があります。

例を挙げましょう。2つのおもちゃがあるとします。1つは犬、もう1つは猫です。

私たちが知っているように、犬は吠え、猫は鳴きます。これら2つは話す方法は同じですが、機能や実装が異なります。発言ボタンのあるリモコンをユーザーに提供するとします。

ユーザーが話すボタンを押すとき、おもちゃはそれが犬であるか猫であるかどうかは関係ありません。

これは、実装が異なるため、抽象クラスではなくインターフェースを使用するのに適したケースです。どうして?覚えて

非抽象メソッドを追加して子クラスをサポートする必要がある場合は、抽象クラスを使用する必要があります。それ以外の場合は、インターフェースを選択します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.