7

PHP内でチェーンすることの利点は知っていますが、次のような状況になっているとしましょう。

$Mail = new MailClass("mail")
        ->SetFrom("X")
        ->SetTo("X")
        ->SetSubject("X")
        ->AddRecipient("X")
        ->AddRecipient("X")
        ->AddRecipient("X")
        ->AddRecipient("X")
        ->AddRecipient("X")
        ->AddRecipient("X")
        ->Send();

オブジェクトを何度も繰り返し再利用することに関する問題、速度やベストプラクティスに従わないことなどの問題はありますか?

Fluent-Interfaceを初めて使用する場合は、これについてもよく読んでください:Fluent-InterfacesのMartin Fowler

このようにプログラムする必要はなく、次のように処理できることを完全に理解しています。

$Mail = new MailClass("mail");
$Mail->AddRecipien(
    array(/*.....*/)
);
$Mail->SetFrom("X");
$Mail->SetTo("X");
$Mail->SetSubject("X");
$Mail->Send();

しかし、私がそのようなオブジェクトを持っているとしましょう:

$Order = new Order()
         ->With(22,'TAL')
         ->With(38,'HPK')->Skippable()
         ->With(2,'LGV')
         ->Priority();

注意してください->With(38,'HPK')->Skippable()、これはこのタイプのプログラミングのためのプロの完璧な例です

4

4 に答える 4

5

何かを検証する必要がある場合は、 AddRecipient Method 自体で検証する方が理にかなっていると思いますが、パフォーマンスはほぼ同じである必要があります。また、メソッドチェーンを使用することの一般的な欠点については認識していません。

于 2010-09-29T13:01:50.457 に答える
2

クラスのインスタンス化から直接チェーンすることはできません。

$Mail = new MailClass("mail") 
            ->SetFrom("X")
            ->SetTo("Y");

最初にインスタンス化してから、インスタンス化されたオブジェクトに対して連鎖する必要があります。

$Mail = new MailClass("mail") ;
$Mail->SetFrom("X")
     ->SetTo("Y");

個々のセッター メソッド内で検証する場合 (必要に応じて)、検証エラーが発生したときに例外をスローするようにする必要があります。エラー時にブール値の false を単純に返すことはできません。そうしないと、チェーンはインスタンスをクラス化するのではなく、ブール値に対して次のメソッドを呼び出そうとします。

致命的なエラー: 23 行目の C:\xampp\htdocs\oChainTest.php の非オブジェクトに対するメンバー関数 SetSubject() の呼び出し

例外をスローする場合は、try... catch 内でチェーンをラップできます

$Mail = new MailClass("mail");
try {
    $Mail->SetFrom("X")
        ->SetTo("Y")
        ->SetSubject("Z");
} catch (Exception $e) {
    echo $e->getMessage();
}

ただし、警告として、これによりインスタンスが部分的に更新された状態のままになり、正常に検証/実行されたメソッドのロールバックは (自分で作成しない限り) なく、例外に続くメソッドは呼び出されません。

于 2010-09-29T13:47:45.400 に答える
1

編集: 質問に一致するように回答を更新しました
関数呼び出しはループよりも遅いです。つまり、たとえばメソッドの連鎖は、配列を受け取り、ループで処理されるメソッドaddRecipient()を呼び出す場合と比較して、パフォーマンスをわずかに低下させます。addRecipients()

さらに、流暢な API までのより洗練されたメソッドチェーンでは、最後に呼び出されたメソッドに関連するデータの追加の簿記が必要になる場合があります。これにより、すべてのメソッドがチェーンが構築された同じオブジェクトを返すため、次の呼び出しがそのデータで作業を継続できるようになります。あなたの例を見てみましょう:

...
->With(22, 'TAL')
->With(38, 'HPK')->Skippable()
->With(2, 'LGV')
...

これは、 がではなくSkippable()に適用されることを覚えておく必要があります。(38, 'HPK')(22, 'TAL')

ただし、コードがループ内で非常に頻繁に呼び出される場合や、Web サーバーへの同時要求が多すぎて限界に近づく場合 (負荷の高い Web サイトの場合) でない限り、パフォーマンスの低下に気付くことはほとんどありません。 .

もう 1 つの側面は、メソッド チェーン パターンがエラーを通知するために例外の使用を強制することです (これが悪いことだと言っているわけではなく、従来の「関数の呼び出しと結果のチェック」スタイルのコーディングとは異なるだけです)。

ただし、通常、属するオブジェクト以外の値を生成する関数があります (たとえば、オブジェクトとアクセサーのステータスを返す関数など)。API のユーザーが、新しいメソッドに遭遇するたびにドキュメントを参照せずに、連鎖可能な関数とそうでない関数を判断できることが重要です (たとえば、すべてのミューテーターとミューテーターのみが連鎖をサポートするというガイドラインなど)。


元の質問への回答:

[...] 私が連鎖に関して抱えている問題は、追加の検証を実際に実行できないという事実です [...]

または、すべてのプロパティを設定した後に呼び出す専用の検証メソッドを実装し、検証失敗の配列を返します (プレーンな文字列または名前付きオブジェクトなどValidationFailure)。

于 2010-09-29T13:06:23.677 に答える
0

これは両刃の剣です。

良い面?これは、クラスを再アドレス指定するよりもクリーンで、ほとんどが構文の変更にすぎませんが、処理が少し高速化されます。各呼び出しを長い形式でループするよりも、この種のチェーンをループする方が望ましいでしょう。

悪い面?これは、人々が最初に慣れるとセキュリティ上の問題を引き起こします。これに入ってくる変数の浄化に熱心に取り組んでください。そうすれば、渡すべきではないものをそこに渡さなくなります。クラスを過度に複雑にしないでください。

  1. 情報を事前に検証します。
  2. ユーザーを事前承認します。

これらのメソッドをループにチェーンしても、パフォーマンス的に問題はありません。

于 2010-09-29T13:09:17.647 に答える