1

これは、Clean Code の慣行により準拠するようにリファクタリングする必要があるかどうか疑問に思っていたコードの一部です。

これは、顧客による一部の注文の返金を担当するクラスです。

class RefundServiceInvoker {

    private $_orders;

    public function refundOrder() {   
        $this->getOrdersFromDB(); //This function gets all orders from DB and sets $_orders
        foreach ($this->_orders as $order) { 
            try {
                $order->refund(); //Some lines may throw an exception when refunded due to some business logic (ex. the order was already shipped)
                $this->updateOrderStatus('refunded')            
            } catch (Exception $e) {                   
                $this->logError($e);
                $this->sendMailToAdmin();
            }
        }
    }
}

もちろん、このコードは元のコードよりも大幅に単純化されています。

私の主な問題は$order->refund();、例外がスローされた場合にキャッチされてDBに記録され、メールが送信されることです。しかし、$this->logError($e);それ自体が例外をスローした場合はどうなるでしょうか? または、メール サーバーがダウンして例外がスローされた場合はどうなるでしょうか。

DB 自体がダウンし$this->getOrdersFromDB();て例外がスローされた場合はどうでしょうか。

私の最初の解決策は、すべてを1つの大きなものにラップすることでしたtry{}catch{}:

public function refundOrder() {   
            try {              
            $this->getOrdersFromDB(); //This function gets all orders from DB and sets $_orders
            foreach ($this->_orders as $order) { 

                    $order->refund(); //Some lines may throw an exception when refunded due to some business logic (ex. the order was already shipped)
                    $this->updateOrderStatus('refunded')            
                } catch (Exception $e) {                   
                    $this->logError($e);
                    $this->sendMailToAdmin();
                }
            }
        }

しかし、それは1つの注文が失敗するとすべてが失敗することを意味します!! 関数全体に 2try{}catch{}つ、注文ごとにもう 1 つ置く必要がありますか? ただし、この場合も、catch 内の関数がキャッチされない例外をスローする可能性があります。

ノート:

このアプリケーションは、Zend フレームワーク 1.11.11 を使用して構築されています。

前もって感謝します。

4

3 に答える 3

3

このような問題を解決する特効薬はありません。関数がスローでき、それを気にする場合は、それをラップtry/アラウンドする必要がありますcatch-それは簡単です。

詳細に移る: アプリのアーキテクチャに関する詳細な情報がなければ、このアプローチまたはそのアプローチのメリットを評価することは実際には不可能ですが、いくつかの一般的な提案を次に示します。

  • を呼び出す前に前提条件を確認してくださいrefundOrder。注文が正常に読み込まれたことを確認してください。操作しようとしている注文がすべて返金可能であることを確認してください (ビジネス ロジックのために返金できない注文を返金しようとする目的は何ですか? 返金を試みる前に、ユーザー/オペレーターにこれを通知すべきではありませんか?) .
  • 複数のレベルのtry/catchを使用してくださいrefundOrder。外側のブロックは、本当に予期しないエラーをキャッチすることを目的としていrefundOrderます。アプリの他の部分でもそれをやりたくないですか? 最も内側のtry/catchは、1 つの返金不可の注文ですべてのプロセスが強制終了されないようにするために必要です。
于 2012-04-18T12:43:56.897 に答える
1

すべての例外をログに記録してメールで送信する必要がある場合は、次のようなものが必要です。

class RefundServiceInvoker {

   private $_orders;

   public function refundOrder() {
      try {
         $this->getOrdersFromDB();
         foreach ($this->_orders as $order) {
            try {
               $order->refund();
            } catch (MyBusinessException $e) {
               # deals with the problematic $order without stopping the loop
               $this->logError($e);
               $this->sendMailToAdmin();
            }
            $this->updateOrderStatus('refunded');
         }
      } catch(Exception $e) {
         # deals with unexpected bugs
         $this->logError($e);
         $this->sendMailToAdmin();
      }
   }
}

ただし、たとえばサーバーがオフラインのときに例外がスローされないように、logメソッドとmailメソッド内にtry/catchを配置する必要があります。そうしないと、ログ/メールが失敗したときに$ordersループが停止します。

払い戻し()メソッドでビジネス例外のみをログに記録/メール送信する必要がある場合は、次のようなものが必要です。

class RefundServiceInvoker {

   private $_orders;

   public function refundOrder() {
      $this->getOrdersFromDB();
      foreach ($this->_orders as $order) {
         try {
            $order->refund();
         } catch (MyBusinessException $e) {
            # deals with the problematic $order without stopping the loop
            $this->logError($e);
            $this->sendMailToAdmin();
         }
         $this->updateOrderStatus('refunded');
      }
   }
}

その他の例外があると、http 500 –内部サーバーエラーページが表示されます。これは予期しないバグであるため、通常は必要なものです。

これを処理する方法は他にもありますが、ご覧のとおり、ニーズによって異なります。

于 2012-04-18T13:12:56.590 に答える
0

logError($e)およびはおそらく最後の手段としてsendMailToAdmin()、通常は try/catch ブロックで使用される関数であるため、それらが決して例外をスローしないようにします。

function logError($e)
{
    try
    {
        //your logic that may throw an Exception here
    }
    catch {}
}

function sendMailToAdmin($e)
{
    try
    {
        //your logic that may throw an Exception here
    }
    catch {}
}
于 2012-04-18T12:50:03.277 に答える