2016-12-08 5 views
1

メソッドのパラメータとしてサブタイプを使用して、子クラスのメソッドをオーバーライドするときにPHPで矛盾があるようです。私はコードで説明している場合それは簡単です:PHPでサブタイプパラメータを使用してメソッドをオーバーライドするときの動作が矛盾します

interface IngredientInterface {} 
interface TomatoInterface extends IngredientInterface {} 

class Tomato implements TomatoInterface {} 

class Soup { 
    public function __construct(IngredientInterface $ingredient) {} 
    public function foo(IngredientInterface $ingredient) {} 
} 

class TomatoSoup extends Soup { 
    public function __construct(TomatoInterface $tomato) { parent::__construct($tomato); } 
    public function foo(TomatoInterface $ingredient) { parent::foo($ingredient); } 
} 

一つは、エラー報告の動作は()メソッドオーバーライド__construct()とfooの間で同一であることを期待するだろうが、そうではありません。

__construct()メソッドはPHP 5.5.38、5.6.19にエラーを生成せず、7.0.4

のfoo()メソッドは、5.5.38および5.6.19に次のエラーを生成します。

Strict Standards: Declaration of TomatoSoup::foo() should be compatible with Soup::foo(IngredientInterface $ingredient) in H:\webroot\test.php on line 16 

および7.0.4で:

Warning: Declaration of TomatoSoup::foo(TomatoInterface $ingredient) should be compatible with Soup::foo(IngredientInterface $ingredient) in H:\webroot\test.php on line 16 

今、私は、エラーの種類がE_WARNINGにE_STRICTから変更されたことを心配していないよ、私は罰金の解析コンストラクタの矛盾にもっと心配だけど、 foo( )メソッドではありません。

これはPHPのバグですか?私はそれをbugs.php.netに報告すべきでしょうか?

答えて

0

あなたがクラスを拡張している場合は、サブタイプを持つようにしたいんなぜあなたはスーパータイプIngredientInterfaceを持っている場合、あなたはコンストラクタにし、メソッドfooにIngredienteInterfaceのサブタイプであるすべてのオブジェクトを渡すことができます(グッドプラクティスリスコフの置換を覚えています原則)、そしてなぜあなたはインターフェースを拡張したいのですか?あなたが子供のクラスのスーパータイプを使用する場合

結果は同じである(インタフェース棲み分け原理を覚えている)が、私はあなたがよりあなたのコードを少し見直しを持っていると思う、SOLID原則は開始

の良い点です
<?php 

interface IngredientInterface {} 
interface TomatoInterface extends IngredientInterface {} 

class Ingredient implements IngredientInterface {} 
class Tomato implements TomatoInterface {} 

class Soup { 
    public function __construct(IngredientInterface $ingredient) {} 
    public function foo(IngredientInterface $ingredient) {} 
} 

class TomatoSoup extends Soup { 
    public function __construct(IngredientInterface $tomato) { parent::__construct($tomato); } 
    public function foo(IngredientInterface $ingredient) { parent::foo($ingredient); } 
} 

$tom = new TomatoSoup(new Tomato()); 
$tom->foo(new Tomato()); 

$tom2 = new TomatoSoup(new Ingredient()); 
$tom2->foo(new Ingredient()); 
+0

ご返信ありがとうございます。はい、あなたのコードは正常に動作することに同意します。これに対応して、ISPに違反しないインターフェースを拡張することに問題はありません。また、必ずしもメソッド引数をサブタイプ化する必要はありませんが、SOLIDに違反しない他の方法があります。私はPHPがメソッド内のLSPの違反を防ぐことを心配していますが、コンストラクタでそれを許可しています。 @DeveloperChrisは、この質問でそれを説明しています... PHPの乗組員が怠け者になったようです:(http://stackoverflow.com/questions/13423494/why-is-overriding-method-parameters-a-violation-of-strict-standards -in-php –

関連する問題