16

私がグーグルで調べてきたように、インターフェイスを使用すると複数の継承がどのように行われるかを理解しようとしています。

class A
{
 function do1(){}
 function do2(){}
 function do3(){}
}

class B extends A
{
 function do4(){}
 function do5(){}
 function do6(){}
}

class C extends B
{
}

上記の例では、クラス C はクラス A と B のすべてのメソッドを持ちます。ただし、クラス B もクラス A のすべてのメソッドを持ちますが、これは必ずしも望ましいことではありません。

私の検索では、以下のように、メソッドをクラスに移動してインターフェイスを作成することにより、インターフェイスを使用してこの問題を解決することができました。

interface A
{
     function do1();
     function do2();
     function do3();
}

interface B
{
     function do4();
     function do5();
     function do6();
}

class C implements A, B
{
     function do1(){}
     function do2(){}
     function do3(){}
     function do4(){}
     function do5(){}
     function do6(){}
}

すべてのコードが新しいクラスにあるため、これで問題がどのように解決されるかはわかりません。クラス A を元のように使用したい場合は、インターフェイス A を実装する新しいクラスを作成し、同じコードを新しいクラスにコピーする必要があります。

足りないものはありますか?

4

5 に答える 5

28

PHP には多重継承がありません。ただし、PHP 5.4 を使用している場合は、トレイトを使用して、少なくともすべてのクラスがコードをコピーする必要がないようにすることができます。

interface A {
    public function do1();
    public function do2();
    public function do3();
}

trait Alike {
    public function do1() { }
    public function do2() { }
    public function do3() { }
}


interface B {
    public function do4();
    public function do5();
    public function do6();
}

trait Blike {
    public function do4() { }
    public function do5() { }
    public function do6() { }
}


class C implements A, B {
    use Alike, Blike;
}

class D implements A {
    use Alike;

    // You can even "override" methods defined in a trait
    public function do2() { }
}

ただし、インターフェイスを実装し、トレイトを使用する (または、もちろん、独自の実装を提供する) 必要があります。また、C と D は、両方とも A インターフェースを実装している場合を除いて、まったく関係がありません。トレイトは基本的にインタプリタ レベルのコピー アンド ペーストであり、継承には影響しません。

于 2012-12-20T05:56:06.797 に答える
23

インターフェイスについて最初に理解しておくべきことは、インターフェイスは継承には使用されないということです。これは非常に重要なことです。複数のクラスで同じ具体的なコードを共有しようとしている場合、それはインターフェイスの目的ではありません。

2 番目に理解しておくべきことは、クライアント コードとサービス コードの違いです。

クライアント コードは基本的に、一連のデータ要求の「最後のステップ」です。MVC のコントローラーまたはビューは、クライアント コードと見なすことができます。一方、モデルはサービスコードと見なすことができます。

インターフェイスは、クライアント コードがサービスから取得するデータの種類に一貫性を持たせることを目的としています。または、別の考え方として、インターフェイスは、サービスがクライアント コードからの要求と互換性があることを確認する方法です。それが彼らがするすべてです。複数のクラスが共有できる実装ではなく、文字通り、データにアクセスするためのインターフェイスを提供します。

具体例を挙げると:

クライアント コード - ユーザーのフォーラム プロファイルの ProfileViewController クラス

class ProfileViewController
{
    public function showProfile(User $user)
    {
         $user->getProfile();
    }
}

Service Code - データを取得し、それを要求しているクライアント コードに渡す User モデル

class User
{
    public function getProfile()
    {
         $profile = Do some SQL query here or something
         return $profile;
    }
}

ここで、後でユーザーをメンバー、管理者、レフリー、モデレーター、ライター、編集者などに分割し、それぞれに独自の種類のプロファイルがあるとします。(たとえば、独自のカスタム クエリ、またはデータ、またはあなたが持っているもの)

ここには 2 つの問題があります。

  1. そこに渡すものには getProfile() メソッドが含まれていることを保証する必要があります。
  2. User オブジェクト以外を渡すと、showProfile() は失敗します。

1 は、抽象クラスとメソッド (またはインターフェイス) を使用して簡単に解決できます。2 も最初は簡単に思えます。なぜなら、モデレーター、管理者、およびメンバーをすべてユーザー基本クラスのサブクラスにすることができるからです。

しかし、その後、USER プロファイルに加えて、汎用プロファイルが必要になった場合はどうなるでしょうか。おそらく、スポーツ選手のプロフィールや有名人のプロフィールを表示したいでしょう。ユーザーではありませんが、プロファイル/詳細ページがあります。

これらはユーザーではないため、User のサブクラスと見なしても意味がない場合があります。

だから今、あなたは少し立ち往生しています。showProfile() は、User オブジェクト以上のものを受け入れることができる必要があります。実際、最終的にそこに渡したいオブジェクトのタイプはわかりません。しかし同時に、常に $user->getProfile() を取得できるようにしたいので、そこに渡すものはすべて、渡されるのに十分な汎用性が必要であり、具体的な getProfile() メソッドを実装する必要があります。

解決?インターフェイス!!!!!

最初のいくつかのサービス コード

// First define an interface for ANY service object that will have a profile

interface IHasProfile
{
    public function getProfile();
}


// Next, define the class for an object that should have a profile. I'll do a bunch for the sake of an example...

class User implements IHasProfile
{
    public function getProfile()
    {
         $profile = Your unique user profile query here
         return $profile;
    }
}


class Celebrity implements IHasProfile
{
    public function getProfile()
    {
         $profile = Your unique celebrity profile query here
         return $profile;
    }
}


class Car implements IHasProfile
{
    public function getProfile()
    {
         $profile = Your unique vehicle profile query goes here
         return $profile;
    }
}

次に、それを使用するクライアント コード

class ProfileViewController
{
    public function showProfile(IHasProfile $obj)
    {
         $obj->getProfile();
    }
}

そして、あなたはそれを持っています。showProfile() は十分に抽象化されているため、どのオブジェクトを取得するかは問題ではありません。オブジェクトが public getProfile() メソッドを持っていることのみを問題とします。これで、心ゆくまで新しいタイプのオブジェクトを作成できるようになりました。それらがプロファイルを持つことを意図している場合は、それらに「implements IHasProfile」を与えるだけで、自動的に showProfile() で動作します。

不自然な例ですが、少なくともインターフェイスの概念を説明する必要があります。

もちろん、単に「怠惰」で、オブジェクトをまったく型キャストせずに、任意のオブジェクトを渡すことができるようにすることもできます。しかし、それは完全に別のトピックです ;)

于 2013-07-20T00:02:32.180 に答える
5

インターフェースのみ多重継承可能!

私の出力など:

php > interface A{};
php > interface B{};
php > interface C extends A,B{};
php > class D implements C{};
php > $d = new D();
php > echo ($d instanceof A);
1
  • A および B インターフェイスを作成し、C インターフェイスはそれらを拡張します。
  • Cインターフェースを実装するDクラスを取得した後
  • 最後に、$d object が instanceof A インターフェイスであるかどうかを尋ねます。そうです。

lulz のために、D および stdclass クラスを拡張する E クラスを作成しようとすると、エラーが発生します。

php > class E extends D, stdclass{};
PHP Parse error:  syntax error, unexpected ',', expecting '{' in php shell code on line 1

Parse error: syntax error, unexpected ',', expecting '{' in php shell code on line 1
于 2015-06-29T17:19:33.150 に答える
1

OOPサポートされている多くの言語のように、PHP では多重継承はできません。

ここで同様のトピックを参照してください。トピックはありAS3ますが、答えを提供します。

特にインターフェースを使用して解決することについて答えるには、同じ投稿で答えますここ

于 2012-12-20T05:54:55.910 に答える