5

アップグレードする前に、既存のコードを PHP5.4 でテストしています。PHP が継承モデルを強化したため、次のコードが機能しなくなっていることがわかりました。この引き締めのため、私はSOLID、特にLiskov の代入原則(私は独学のプログラマーです) について読んでおり、コードを改善して将来の「引き締め」に悩まされないようにしています。

interface IComparable {
    public function equals(self $other);
}

class A implements IComparable{
    protected $var;

    public function __construct($v){
        $this->var=$v;
    }

    public function equals(self $other){
        return ($this->var == $other->var) ? 'equal' : 'different';
    }
}

$a1= new A(7);
$a2= new A(5);
$a3= new A(5);

echo $a1->equals($a2),"\n";
echo $a2->equals($a3),"\n";

PHP 5.3 の結果:

  • 違う
  • 同等

PHP 5.4 の結果:

PHP 致命的なエラー: A::equals() の宣言は IComparable::equals(IComparable $other) と互換性がある必要があります

次のようにコードを記述すれば、php5.4 エラーを回避できます。

interface IComparable {
    public function equals($other);
}

class A implements IComparable{
    protected $var;

    public function __construct($v){
        $this->var=$v;
    }

    public function equals($other){
        if(get_class($other) != get_class($this)) return false;
        return ($this->var == $other->var) ? 'equal' : 'different';
    }
}

しかし、関数は明らかに引数の型を受け入れないため、修正はリスコフの置換原則に準拠していますか? そうでない場合、必要なことを実行し、同じタイプの 2 つのオブジェクトを比較し、適切な OOD 原則に準拠する継承可能な関数をコーディングするにはどうすればよいでしょうか?

4

2 に答える 2

3

まず第一に、PHP 5.3 の動作はバグであるため、他のアプローチを判断するための尺度として使用することはできません。

今後、LSP はバージョン 5.3 のコードですでに違反されています。検討:

interface IComparable {
    public function equals(self $other);
}

これは、「任意のものIComparableは自分自身を他の任意のものと比較できる」ことを示していますIComparable(比較のセマンティクスは議論にとって重要ではありません)。その後class A、 は LSP に違反します。これは、たまたまインスタンスとなるものとの比較のみをサポートしているためです。IComparableA

PHP 5.4 バージョンは LSP に違反していません。これは、新しいバージョンのIComparableが「自分自身を他のオブジェクトと比較できる」と述べているためclass Aです。

5.3 バージョンの契約を維持することが意図されている場合は、以下をおIComparable読みください。

interface IComparable {
    public function equals(IComparable $other);
}

もちろん、class A同じ署名を使用します。これは LSPに違反せず、両方のバージョンで正しく機能します。

あなたの意図が「IComparableインスタンスが同じ型のインスタンスと比較できる」と宣言することであった場合、このコントラクトはメソッド シグネチャと型ヒントを使用して表現できないため、うまくいきません。

更新:あなたの意図は「このクラスのインスタンスは自分自身を比較できる」と宣言することであり、これIComparableを忘れないようにすることを単に意図していたことがわかりました。

この場合、解決策は単純にの署名を忘れてIComparable使用することです。必要なメソッドを定義することを覚えておくようにコンパイラが強制することはありませんが、それは私見では小さな問題です (特に、インターフェイスが 1 つのメソッドしか宣言していないため)。selfA::compare()

于 2012-05-09T13:31:30.843 に答える
0

より堅牢にするために、インターフェイスとクラスを次のように記述する必要があると思います。

interface IComparable
{
    /** 
     *  @return boolean 
     */
    public function equals(IComparable $other);

    /**
     *  @return mixed
     */
    public function getValue();
}


class A implements IComparable{
    protected $var;

    public function __construct($v){
        $this->var=$v;
    }

    /**
     *  @return mixed
     */
    public function getValue()
    {
       return $this->var;
    }

    /** 
     *  @param  IComparable $other
     *  @return boolean 
     */
    public function equals(IComparable $other)
    {
        return ( $this->getValue() === $other->getValue() );
    }
}

PHP の self キーワードは現在のクラスを参照します。メソッドの引数が何であるかがわかりにくくなるため、型ヒント引数に使用しないことをお勧めします。

equals と Liskov Substitution の実装に関して、これはあなたが触れている興味深いテーマです。平等とリスコフについての興味深い議論については、ここを参照してください。

于 2012-05-09T13:41:07.263 に答える