web-dev-qa-db-ja.com

PHPインターフェースによる多重継承

私はグーグルしてきたように、インターフェイスを使用して多重継承がどのように与えられるかを理解しようとしています。

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を実装する新しいクラスを作成し、同じコードを新しいクラスにコピーする必要があります。

行方不明のものはありますか?

16
tdbui22

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

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インターフェースの実装を除いて、まったく関連していません。特性は、基本的にはインタプリタレベルのコピーと貼り付けであり、継承には影響しません。

29
cHao

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

次に理解する必要があるのは、クライアントコードとサービスコードの違いです。

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

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

具体的な例を挙げましょう:

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

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

サービスコード-データを取得し、それを要求しているクライアントコードに渡すユーザーモデル

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

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

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

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

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

しかし、その後、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()が十分に抽象化され、取得したオブジェクトwhatを気にしないようになりました。オブジェクトにパブリックgetProfile()メソッドがあることだけが気になります。これで、新しいタイプのオブジェクトを心に込めて作成できるようになりました。オブジェクトにプロファイルを持たせる場合は、「IHasProfileを実装」するだけで、自動的にshowProfile()で動作します。

一種の不自然な例ですが、少なくともインターフェースの概念を示しているはずです。

もちろん、単に「怠惰」でオブジェクトを型キャストしないで、ANYオブジェクトを渡すこともできます。ただし、これは完全に別のトピックです;)

23
AgmLauncher

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

そのための私の出力など:

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オブジェクトが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
4
tonicospinelli

PHPでは多くのOOPでサポートされている言語と同様に、多重継承は不可能です

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

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

お役に立てれば

1
Solow Developer

here が@tonicospinelliに伝えたように、確かに、PHPはインターフェイスの多重継承を許可します、しかしそれは明確に説明されていません、ただ 例を与えられた

多重継承のしくみPHPは、Interfacesを実装するTraitsを使用してこれらを渡します。

「マルチインターフェイス」(1)を実装するClassを宣言したら、既に定義されているTraitsを使用して、継承がよく行われた。

(1):「マルチインターフェース」と言って、他の複数のインターフェースから拡張されるインターフェースを実装するクラスを意味します

0
xsubira