22

次のPHPインターフェースを検討してください。

interface Item {
    // some methods here
}

interface SuperItem extends Item {
    // some extra methods here, not defined in Item
}

interface Collection {
    public function add(Item $item);
    // more methods here
}

interface SuperCollection extends Collection {
    public function add(SuperItem $item);
    // more methods here that "override" the Collection methods like "add()" does
}

PHPStormを使用していますが、これを行うと、IDEでエラーが発生し、基本的にadd()inSuperCollectionの定義が拡張するインターフェイスの定義と互換性がないことを示しますCollection

ある意味では、メソッドのシグニチャが「オーバーライド」するシグニチャと正確に一致しないため、これが問題であることがわかります。ただし、これはSuperItemextendsのように互換性があると思いますので、と同じようItemに表示します。add(SuperItem)add(Item)

これがPHP(バージョン5.4以降)でサポートされているかどうか知りたいのですが、IDEにバグがあり、これを適切にキャッチできない可能性があります。

4

7 に答える 7

15

いいえ、PHPはどのバージョンでもこれをサポートしていないと確信しています。むしろ、インターフェイスのポイントを打ち負かすでしょう。

インターフェイスのポイントは、同じインターフェイスを参照する他のコードとの固定契約を提供することです。

たとえば、次のような関数について考えてみます。

function doSomething(Collection $loopMe) { ..... }

この関数は、インターフェースを実装するオブジェクトを受け取ることを期待していCollectionます。

Collection関数内で、プログラマーは、オブジェクトがそれらのメソッドを実装することを知っているので、で定義されたメソッドへの呼び出しを書くことができます。

このようなオーバーライドされたインターフェイスがある場合は、SuperCollectionオブジェクトが関数に渡される可能性があるため、これに問題があります。Collection継承によるオブジェクトでもあるので動作します。add()しかし、関数内のコードは、メソッドの定義が何であるかを認識していることを確認できなくなりました。

インターフェースは、定義上、固定契約です。不変です。

別の方法として、インターフェースの代わりに抽象クラスを使用することを検討できます。これにより、非厳密モードでオーバーライドできますが、同じ理由で、厳密モードを使用するとエラーが発生します。

于 2013-02-21T20:44:26.413 に答える
3

回避策として、インターフェイスでPHPDocブロックを使用しています。

interface Collection {
   /**
    * @param Item $item
    */
    public function add($item);
    // more methods here
}

interface SuperCollection extends Collection {
    /**
    * @param SuperItem $item
    */
    public function add($item);
    // more methods here that "override" the Collection methods like "add()" does
}

このように、インターフェースを適切に使用している場合、IDEはいくつかのエラーをキャッチするのに役立ちます。同様の手法を使用して、戻り値の型をオーバーライドすることもできます。

于 2016-04-09T14:33:36.010 に答える
3

2014年11月にリリースされたPHP7.4では、型の差異が改善されています。

質問のコードは無効のままです:

interface Item {
    // some methods here
}

interface SuperItem extends Item {
    // some extra methods here, not defined in Item
}

interface Collection {
    public function add(Item $item);
    // more methods here
}

interface SuperCollection extends Collection {
    public function add(SuperItem $item); // This will still be a compile error
    // more methods here that "override" the Collection methods like "add()" does
}

インターフェイスは、それを実装するすべてのものがのパラメータとしてCollectionタイプの任意のオブジェクトを受け入れることができることを保証するためです。Itemadd

ただし、次のコードはPHP7.4で有効です。

interface Item {
    // some methods here
}

interface SuperItem extends Item {
    // some extra methods here, not defined in Item
}

interface Collection {
    public function add(SuperItem $item);
    // more methods here
}

interface SuperCollection extends Collection {
    public function add(Item $item); // no problem
    // more methods here that "override" the Collection methods like "add()" does
}

この場合Collection、それが任意のを受け入れることができることを保証しますSuperItem。すべてSuperItemのsはItemsでSuperCollectionあるため、他のタイプのを受け入れることができることも保証しながら、この保証も行いますItem。これは、共変性メソッドのパラメーター型として知られています。

以前のバージョンのPHPには、限定された形式の型の差異があります。他のインターフェースが質問のとおりであると仮定すると、は次のSuperCollectionように定義できます。

interface SuperCollection extends Collection {
    public function add($item); // no problem
    // more methods here that "override" the Collection methods like "add()" does
}

addこれは、メソッドに渡される可能性のあるすべての値を意味すると解釈できます。もちろん、これにはすべてItemのが含まれるため、これはタイプセーフであるか、または一般に渡される可能性があるように文書化された不特定のクラスの値を意味すると解釈できmixed、プログラマーは関数で何が機能するかについて他の知識を使用する必要があります。

于 2019-07-06T17:05:47.803 に答える
2

メソッドの引数は変更できません。

http://php.net/manual/en/language.oop5.interfaces.php

于 2013-02-21T20:38:40.657 に答える
1

インターフェイスを拡張してメソッド定義を変更することはできません。SuperItemがItemを拡張している場合は、Collectionインターフェイスを実装するクラスを問題なく通過する必要があります。

しかし、あなたが本当にやりたいことに基づいて、あなたは試すことができます:

  • SuperItemのメソッドが少し異なるインターフェイスを作成し、それを実装します。

    interface SuperCollection extends Collection {
        public function addSuper(SuperItem $superItem);
    }
    
  • デコレータパターンを使用して、拡張せずにほぼ同じインターフェイスを作成します。

    interface Collection {
        public function add(Item $item);
        // more methods here
    }
    
    interface SuperCollection {
        public function add(SuperItem $item);
        // more methods here that "override" the Collection methods like "add()" does
    }
    

    次に、このインターフェイスを使用するデコレータ(抽象)クラス:

    class BasicCollection implements Collection {
        public function add(Item $item)
        {
        }
    }
    
    class DecoratingBasicCollection implements SuperCollection {
        protected $collection;
    
        public function __construct(Collection $collection)
        {
            $this->collection = $collection;
        }
    
        public function add(SuperItem $item)
        {
            $this->collection->add($item);
        }
    }
    
于 2018-03-06T10:55:26.570 に答える
0

問題はIDEにはありません。PHPでは、メソッドをオーバーライドすることはできません。また、互換性は反対方向にのみあります。親クラスのインスタンスを安全に期待して、サブクラスを受け取ることができます。ただし、サブクラスを期待する場合、親クラスを受け取った場合は安全ではありません。サブクラスは、親に存在しないメソッドを定義する場合があります。しかし、それでも、メソッドをオーバーライドすることはできません

于 2013-02-21T20:38:51.673 に答える
0

オーバーロードが必要になる可能性のあるメソッド(PHPはサポートしていません)がある場合、メソッド引数の1つ(通常は最後)が配列であることを確認します。このようにして、必要なものは何でも渡すことができます。次に、関数内でさまざまな配列要素をテストして、通常はselect/caseで実行する必要のあるメソッドのルーチンを教えてくれます。

于 2015-12-11T22:11:58.050 に答える