web-dev-qa-db-ja.com

例外対エラーオブジェクト対単なるfalse/nullを使用する場合

私はプラグインを書いている最中で、エラー処理のさまざまなアプローチをいつ使うべきかを判断しようとしています。

私が検討している3つの方法があります。

  • 例外を投げる(カスタムクラス)
  • エラーオブジェクトを返す(WP_Errorの拡張)
  • Null/falseを返すだけ

私が考えているいくつかの状況

  • 存在しないレジストリに格納されているオプションを取得/設定しようとしています
  • 無効な値をメソッドに渡す(これはめったにないはずです)
  • クラスのオーバーローダが解決できないメソッドを呼び出す

提案? WordPressプラグインを書くことには特別な考慮があるので、一般的なPHPボードでこれを尋ねる価値があるかどうかはわかりません。

8
Doug Wollison

このような選択は個人的な好みであるため、ここで決定的な答えを出すことは不可能だと思います。

以下はmyアプローチであり、私はそれが正しいアプローチであるとは思いません。

確かに言えることは、3番目のオプションを避けるべきだということです。

Null/falseを返すだけです

これは異なる側面の下では悪いです:

  • 戻り型の一貫性
  • 関数の単体テストが難しくなります
  • 戻り型(if (! is_null($thing))...)の条件付きチェックを強制し、コードを読みにくくします

私は頻繁にOOPを使用してプラグインをコーディングしますが、オブジェクトメソッドは何かがうまくいかない場合に例外をスローすることがよくあります。

そうすることで、私は:

  • 戻り型の一貫性を達成する
  • コードを単純に単体テストする
  • 返される型の条件付きチェックは不要です

ただし、WordPressプラグインで例外をスローすると、何もcatchしないため、絶対的にnotの致命的なエラーが発生します。 =生産において特に望ましい。

この問題を回避するために、通常、メインプラグインファイルに「メインルーチン」を配置し、try/catchブロックでラップします。これにより、実稼働環境で例外をキャッチし、致命的なエラーを防ぐことができます。

クラスの大まかな例:

# myplugin/src/Foo.php

namespace MyPlugin;

class Foo {

  /**
   * @return bool
   */
  public function doSomething() {
     if ( ! get_option('my_plugin_everything_ok') ) {
        throw new SomethingWentWrongException('Something went wrong.');
     }

     // stuff here...

     return true;
  }
}

メインプラグインファイルから使用する:

# myplugin/main-plugin-file.php

namespace MyPlugin;

function initialize() {

   try {

       $foo = new Foo();
       $foo->doSomething();      

   } catch(SomethingWentWrongException $e) {

       // on debug is better to notice when bad things happen
       if (defined('WP_DEBUG') && WP_DEBUG) {
          throw $e;
       }

       // on production just fire an action, making exception accessible e.g. for logging
       do_action('my_plugin_error_shit_happened', $e);
   }
}

add_action('wp_loaded', 'MyPlugin\\initialize');

もちろん、現実の世界では、さまざまな種類の例外をスローしてキャッチし、例外に応じて異なる動作をする場合がありますが、これは方向性を与えるはずです。

私がよく使用する(言及しない)別のオプションは、エラーが発生していないかどうかを確認するフラグを含むオブジェクトを返すことですが、戻り値の型の一貫性を保ちます。

これは、そのようなオブジェクトの大まかな例です。

namespace MyPlugin;

class Options {

   private $options = [];
   private $ok = false;

   public function __construct($key)
   {
      $options = is_string($key) ? get_option($key) : false;
      if (is_array($options) && $options) {
         $this->options = $options;
         $this->ok = true;
      }
   }

   public function isOk()
   {
     return $this->ok;
   }
}

これで、プラグインのどこからでも次のことができます。

/**
 * @return MyPlugin\Options
 */
function my_plugin_get_options() {
  return new MyPlugin\Options('my_plugin_options');
}

$options = my_plugin_get_options();
if ($options->isOk()) {
  // do stuff
}

上記のmy_plugin_get_options()Optionsクラスのインスタンスを常に返す方法に注意してください。この方法で、常に戻り値を渡すことができ、さらにtype-hintを使用する他のオブジェクトにそれを注入できます異なります。

関数がエラーの場合にnull/falseを返した場合、それを渡す前に、返された値が有効かどうかの確認を強制されていました。

同時に、オプションインスタンスに問題があることを明確に理解する方法があります。

これは、エラーが、デフォルトまたは適切なものを使用して簡単に回復できるものである場合に適したソリューションです。

5
gmazzap