何时使用异常vs错误对象vs普通false / null


8

我正在编写插件,正在尝试确定何时使用不同的错误处理方法。

我正在考虑三种方法:

  • 引发异常(自定义类)
  • 返回错误对象(WP_Error的扩展名)
  • 只需返回null / false

我正在考虑的一些情况

  • 尝试获取/设置注册表中不存在的选项
  • 将无效的值传递给方法(应该很少)
  • 调用类的重载程序无法解析的方法

有什么建议吗?由于编写WordPress插件有一些特殊的注意事项,因此我不确定是否值得在一般的PHP板上进行询问。

Answers:


5

我认为不可能在这里给出确切的答案,因为这样的选择是个人喜好。

考虑以下是我的方法,我不认为这是正确的方法

我可以肯定地说的是,您应该避免第三个选择:

只需返回null / false

在不同方面这是不好的:

  • 返回类型约束
  • 使功能更难以进行单元测试
  • 对返回类型(if (! is_null($thing))...)强制执行条件检查,使代码更难阅读

我经常使用OOP编写插件代码,而发生错误时,我的对象方法经常抛出异常。

这样做,我:

  • 完成返回类型的一致性
  • 使代码易于单元测试
  • 不需要对返回的类型进行条件检查

但是,在WordPress插件中引发异常意味着没有任何东西可以捕获它们,最终导致致命错误,这绝对是希望的,特别是在生产中。

为避免此问题,我通常在主插件文件中有一个“主例程”,将其包装在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发生错误,则在传递该函数之前,您必须检查返回的值是否有效。

同时,您可以清楚地了解选项实例是否存在问题。

如果错误是可以使用默认值或任何合适的方式容易恢复的东西,那么这是一个很好的解决方案。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.