Quando usar Exceptions vs Error Objects vs simplesmente false / null

8

Estou no processo de escrever um plug-in e estou tentando avaliar quando usar abordagens diferentes para lidar com erros.

Existem três métodos que estou considerando:

  • Lançando uma exceção (classe personalizada)
  • Retornando um objeto de erro (extensão de WP_Error)
  • Apenas retorne null / false

Algumas situações que estou considerando

  • Tentando obter / definir uma opção armazenada no registro que não existe
  • Transmitindo um valor inválido para um método (que deve ser raro)
  • Chamando um método que o sobrecarregador da classe não pode resolver para

Sugestões? Já que escrever um plugin para WordPress tem algumas considerações especiais, eu não tenho certeza se valeria a pena perguntar isso em um quadro geral de PHP.

    
por Doug Wollison 21.02.2016 / 22:08

1 resposta

5

Acho impossível dar uma resposta definitiva aqui, porque escolhas como essa são preferências pessoais.

Considere que o que segue é a abordagem my , e eu não tenho nenhuma presunção de que é o certo .

O que posso dizer com certeza é que você deve evitar sua terceira opção:

  

Apenas retorne null / false

Isso é ruim sob um aspecto diferente:

  • devolução do tipo de retorno
  • dificulta as funções do teste unitário
  • forçar a verificação condicional no tipo de retorno ( if (! is_null($thing))... ), tornando o código mais difícil de ler

Eu, mais do que frequentemente, uso o OOP para codificar plugins, e meus métodos de objeto geralmente lançam exceções quando algo dá errado.

Fazendo isso, eu:

  • efetua o consenso do tipo de retorno
  • simplifique o código para teste unitário
  • não precisa de verificação condicional no tipo retornado

No entanto, lançar exceções em um plug-in do WordPress significa que nada será capturado , terminando em um erro fatal que é absolutamente não desejável, especialmente em produção.

Para evitar esse problema, eu normalmente tenho uma "rotina principal" localizada no arquivo de plug-in principal, que eu envolvo em um bloco try / catch . Isso me dá a chance de pegar a exceção na produção e evitar o erro fatal.

Um exemplo aproximado de uma classe:

# 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;
  }
}

e usando o arquivo do plugin principal:

# 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');
Claro, no mundo real você pode lançar e pegar diferentes tipos de exceção e se comportar de maneira diferente de acordo com a exceção, mas isso deve lhe dar uma direção.

Outra opção que eu uso com freqüência (e você não mencionou) é retornar objetos que contenham um sinalizador para verificar se nenhum erro aconteceu, mas mantendo a consistência do tipo de retorno.

Este é um exemplo aproximado de um objeto como esse:

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;
   }
}

Agora, em qualquer lugar do seu plug-in, você pode fazer:

/**
 * @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
}

Observe como my_plugin_get_options() acima sempre retorna uma instância de Options class, dessa forma você sempre pode passar o valor de retorno, e até mesmo injetá-lo em outros objetos que usam dica de tipo agora preocupa que o tipo seja diferente.

Se a função tivesse retornado null / false em caso de erro, antes de passá-la, você teria sido forçado a verificar se o valor retornado é válido.

Ao mesmo tempo, você tem uma maneira clara de entender se algo está errado com a instância da opção.

Esta é uma boa solução caso o erro seja algo que possa ser facilmente recuperado, usando padrões ou o que for adequado.

    
por gmazzap 22.06.2016 / 17:04