2011-11-29 14 views
0

Doctrineモデルで関連オブジェクトをコレクションに追加するメソッドを作成していますが、そのコレクションに重複オブジェクトが追加されたときに例外をスローしたいとします。ここでセットに複製を追加しようとすると、どのような例外がスローされますか?

はテスト(秒)です:まず

public function testFluentInterface() 
{ 
    $sport = new Sport(); 
    $this->assertSame($sport, $sport->addCode('ANY'), 
    'Expected Sport to implement fluent interface.' 
); 
} 

public function testCannotAddSameCodeMoreThanOnce() 
{ 
    $code = 'BAZ'; 

    $sport = new Sport(); 
    $sport->addCode($code); 

    try 
    { 
    $sport->addCode($code); 
    $this->fail(
     'Expected error when trying to add the same code to a sport more than once.' 
    ); 
    } 
    catch(/*SomeKindOf*/Exception $e) 
    { 
    } 
} 

、私はOverflowExceptionが、この場合にスローされることが適切かもしれないと思ったが、私は「この値が既に存在する」かどうかは確かではありませんよ

要素をフルコンテナに追加すると例外がスローされます。

ありUnexpectedValueExceptionだが、それは間違った種類の変数により適用可能であると思わ:値は、値のセットと一致しない場合

例外がスローされます。通常、これは、関数が別の関数を呼び出し、戻り値が算術またはバッファー関連のエラーを含まない特定のタイプまたは値であることを期待する場合に発生します。

私はいつもLogicExceptionを使用することができますが、それはこのユースケースのために少しの一般的なようだ:プログラム・ロジックのエラーを表し

例外。このような種類の例外は、コード内の修正に直接つながるはずです。

ここでより適切な選択肢がありますか?私の観察は正しいのですか?一意の値を含むコレクションに複製を追加しようとするときにスローする最も適切なSPL例外は何ですか?

答えて

0

特に、ToniとFrancisのそれぞれの答えに照らして、このシナリオでは例外をスローすると便利だろうかと思います。

トニーのポイントごとに、多くのクラスがすでにこの状況を別々に処理しています。この場合、「失敗」値を返すことはオプションではありません(Sportクラスは流暢なインターフェイスを実装しています)。オブジェクトをコレクションに2回追加しようとすることは、必ずしも「例外的」なケースではありません。

フランシスはまた、PHPの他の構成要素(配列など)がこの種のことに気をつけていないことを知っています。重複したアイテムがコレクションに追加されたときに例外をスローすると、保守性の問題が発生する可能性のある前例のない動作になります。

また、例外をスローすることは、流暢なインターフェースのコンセプトと相反すると考えることができます。とにかく条件付きチェックでチェーンを分割する必要がある場合、開発者がインスタンスにメソッドをチェーンできるようにする点は何でしょうか?言い換えれば

、目標はこれである場合:

$sport 
    ->addCode($codeA) 
    ->addCode($codeB) 
    ->setSomeOtherProperties(...) 
    ->save(); 

そして、それはこれをしなければならないために、開発者を強制的にも意味がありません:

if(! $sport->hasCode($codeA)) 
{ 
    $sport->addCode($codeA); 
} 
// etc. - Why bother having a fluent interface if it's unsafe to use it? 

上記のコードは特に問題となるので、 addCode()はとにかくhasCode()を呼び出す予定であり、実際には開発者に重複計算を強制します。

とのtry/catchを使用すると、はるかに良いではありません。上記のブロックにLogicExceptionから回復しようとすると

try 
{ 
    $sport 
    ->addCode($codeA) 
    ->addCode($codeB) 
    ->setSomeOtherProperties(...) 
    ->save(); 
} 
catch(LogicException $e) 
{ 
    // $sport is now in an unknown state. 
} 

は非現実的であり、それがここでも必要はありません。コードを2回追加しようとすると、Sportオブジェクトが永続化されなくなります。

+1

'addCode()'が何をするのか分かりませんが、重複を黙って無視するか例外を発生させるかは、どれほど危険なのかが分かります。 'addCode()'が同じパラメータで複数回呼び出されても安全に何もできない場合、これは開発者にとって驚くべき振る舞いではありません。あなたはこの条件をまったく指定する必要はないと思います。例外または戻り値もしユーザー*が本当に知っている必要があれば、 'hasCode()'を使うことができます。しかし、このメソッドがより危険で、失敗が大きな問題である場合は、例外をスローします。とにかく流暢に使うのは危険です。 –

+1

これにより、元のテストの性質も変わることに注意してください。パブリックインターフェイスをテストする必要はなくなりますが、コードが2度追加されていないことを保証するためにオブジェクトの内部状態をテストする必要があります。 –

0

例として、Java Collection Framework(つまりSet)の多くのクラスは例外をスローしませんが、falseを返します。

個人的に私はそのように行きます。

+0

ありがとうございました。それは良い点です。残念ながら、この場合、クラスは流暢なインターフェースをサポートしています(つまり、 '$ sport-> addCode()'を呼び出すコードは戻り値が '$ sport'になると期待しています)。 –

+1

この場合、LogicExceptionを選択します。これは、他の2つが誤解を招くことがあるからです(再度、個人的な好みです)。良い仕事と幸運! –

+0

私は流暢なインターフェイスに注意するための質問を更新しました。あなたの提案をもう一度おねがいします。彼らは、私が問題に近づく方法について、いくつかの非常に重要な疑問を提起しました。 –

1

実際に適合するSPL例外はありません。あなたはあなた自身の例外を作成したほうが良いかもしれません:

/** 
* Raised when item is added to a collection multiple times. 
*/ 
class DuplicateException extends RuntimeException {}; 

が、この場合に例外を投げるあなたは、アレイ内の同じキーに同じ値を割り当てるたびに例外をスローするやや同等、ビット抜本的なようです。このケースを検出するために例外の代わりに戻り値を使用することを検討しましたか?

+0

提案してくれてありがとうフランシス。この場合、クラスは流暢なインターフェースを実装しているので、例えば '$ sport-> addCode()'を呼び出すコードは戻り値が '$ sport'であると期待します。 –

+0

私は流暢なインターフェイスに注意するための質問を更新しました。あなたの観測に感謝します。彼らは、私が問題に近づく方法について、いくつかの非常に重要な疑問を提起しました。 –

関連する問題