28

ここにいくつかのスニペットがあります:

  1. コンストラクターメソッドのオーバーライドには、追加のパラメーターがあります。

    class Cat {
        function __construct() {}
    }
    
    class Lion extends Cat {
        function __construct($param) {}
    }
    
  2. (通常の)メソッドのオーバーライドには、追加のパラメーターがあります。

    class Cat {
        function doSomething() {}
    }
    
    class Lion extends Cat {
        function doSomething($param) {}
    }
    

最初のものは機能し、2番目のものはスローしDeclaration of Lion::doSomething() should be compatible with that of Cat::doSomething()ます。

なぜコンストラクタメソッドに対する特別な態度なのか?

4

5 に答える 5

36

それらが異なって扱われる理由を理解するには、リスコフの置換原則を理解する必要があります。

タイプSのオブジェクトo1ごとに、タイプTのオブジェクトo2があり、Tに関して定義されたすべてのプログラムPについて、o1をo2に置き換えても、Pの動作は変わらない場合、SはTのサブタイプになります。 "- BarbaraLiskov、データの抽象化と階層、SIGPLAN Notices、23、5(1988年5月)。

一言で言えば、これは、クラスがどちらかであるかどうかに関係なく、あなたを使用している、LionまたはそれCatを確実に呼び出すことができるはずのクラスを意味しますdoSomething。メソッドシグニチャを変更すると、これは保証されなくなります(ただし、幅を広げることはできますが、幅を狭めることはできません)。

非常に単純な例

public function doSomethingWithFeline(Cat $feline)
{
    $feline->doSomething(42);
}

、あなたはis-a関係を確立したのでLion extends Cat、意味はaをdoSomethingWithFeline受け入れます。ここで、に必要な引数を追加するとします。上記のコードは、その新しいパラメーターを渡していないため、壊れます。したがって、互換性のある署名が必要です。LionCatdoSomethingLion

ただし、サブタイプの依存関係が異なる可能性があるため、 LSPはコンストラクターには適用されません。たとえば、FileLoggerとDBLoggerがある場合、前者のctor(コンストラクター)にはファイル名が必要ですが、後者にはdbアダプターが必要です。そのため、ctorは具体的な実装に関するものであり、クラス間の契約の一部ではありません。

于 2013-03-16T11:18:49.677 に答える
12

リスコフの置換原則は、「SがTのサブタイプである場合、タイプTのオブジェクトをタイプSのオブジェクトに置き換えることができる」と述べています。Catあなたの例では、それはあなたがタイプのオブジェクトをタイプのオブジェクトに置き換えることができるはずであることを意味しますLion

これが、2番目のコードが許可されない理由です。->doSomething()引数なしでメソッドを呼び出すことができなくなるため、この置換を行うことができなくなります。

一方、コンストラクターは、結果のオブジェクトAPIの一部ではないため、リスコフの置換原則の対象ではありません。コンストラクターの署名が一致するかどうかに関係なく、結果のオブジェクトを置き換えることができます。

サブクラスはより具体的で、より多くの依存関係を必要とするため、実際には、サブクラスがより多くのコンストラクター引数を持つことは非常に一般的です。

于 2013-03-16T11:21:03.560 に答える
5

__construct()クラスごとに一意であるため。のコンストラクターLionは、のコンストラクターと同じではありませんが、 extendsで、がないCat場合でも、。を使用して親を拡張できます。LionCatLion__construct()__construct()Lion::__construct()

他のメソッドとは異なり、親の__construct()メソッドとは異なるパラメーターで__construct()がオーバーライドされた場合、PHPはE_STRICTレベルのエラーメッセージを生成しません。

PHPマニュアル:コンストラクタとデストラクタ

他のマジックメソッドは特定の引数を取ります。つまり、引数の数などは常に一貫しています。

クラスがインスタンス化された後、ポリモーフィズム/オーバーライドキックインを実行しますdoSomething()。親クラスは、抽象クラスと同様に、オーバーライドをサポートするために子クラスが一致する必要がある引数と可視性を定義します。

于 2013-03-14T15:52:03.903 に答える
2

コンストラクターは、具体的なオブジェクト専用です。それはそれを生み出します。

他のメソッドは、サブタイプに関する限り、継承されたクラスに関連しているため、これらのメソッドは同じオブジェクトの一部であるため、複数のクラスの定義に分散する場合は互換性があります。

それ以外の場合は、少ししぞうオブジェクトを作成します。


編集:コンストラクター署名を使用して厳密なチェックも導入する場合は、interfaceコンストラクターチェックを追加したPHP5.2以降

実装でコンストラクター署名チェックを強制するために、インターフェースでコンストラクターのサポートが追加されました。PHP 5.2.0以降、インターフェースはコンストラクターを持つことができます。ただし、インターフェイスでコンストラクターを宣言することを選択した場合、そのインターフェイスを実装する各クラスには、ベースインターフェイスコンストラクターのシグネチャと一致するシグネチャを持つコンストラクターが含まれている必要があります。「署名」とは、パラメータと戻り型の定義を意味します。これには、型のヒントが含まれ、データが参照によって渡されるか値によって渡されるかが含まれます。

(以下から取得:その他の機能強化-PHP5.1.xからPHP5.2.xへの移行

于 2013-03-16T11:38:44.160 に答える
1

あなたが説明しているのは、PHPでサポートされていないオーバーロードです。これで、クラスのコンストラクタを作成するときに、そのクラス内でのみ使用され、親コンストラクタはデフォルトでは呼び出されません(コンストラクタとデストラクタを参照してください。手動で呼び出す必要があります) parent::__construct()

クラスにメソッドを作成すると、親メソッドに直接アクセスします。

結論として:

  • コンストラクターはオーバーロードを使用していませんが、クラス自体専用です
  • メソッドはオーバーロードを使用しているため、許可されていません
于 2013-03-14T15:56:21.797 に答える