Kapan harus menggunakan Pengecualian vs Objek Kesalahan vs sekadar false / null

8

Saya sedang dalam proses menulis plugin dan saya mencoba mengukur kapan harus menggunakan berbagai pendekatan penanganan kesalahan.

Ada tiga metode yang saya pertimbangkan:

  • Melempar Eksepsi (kelas khusus)
  • Mengembalikan Objek Kesalahan (ekstensi WP_Error)
  • Kembalikan null / false

Beberapa situasi yang saya pertimbangkan

  • Mencoba untuk mendapatkan / menetapkan opsi yang tersimpan di Registry yang tidak ada
  • Melewati nilai yang tidak valid ke suatu metode (yang seharusnya langka)
  • Memanggil metode yang tidak bisa diselesaikan oleh class 'overloader

Saran? Karena menulis plugin WordPress memiliki beberapa pertimbangan khusus, saya tidak yakin apakah layak menanyakan ini di papan PHP umum.

Doug Wollison
sumber

Jawaban:

5

Saya pikir tidak mungkin memberikan jawaban yang pasti di sini, karena pilihan seperti ini adalah pilihan pribadi.

Pertimbangkan bahwa yang berikut ini adalah pendekatan saya , dan saya tidak memiliki anggapan bahwa itu adalah pendekatan yang benar .

Yang bisa saya katakan dengan pasti adalah bahwa Anda harus menghindari opsi ketiga Anda:

Kembalikan null / false

Ini buruk di bawah aspek yang berbeda:

  • tipe kembali konsinstensi
  • membuat fungsi lebih sulit untuk unit test
  • paksakan pemeriksaan bersyarat pada tipe kembali ( if (! is_null($thing))...) membuat kode lebih sulit dibaca

Saya, lebih sering, menggunakan OOP untuk mengkodekan plugin, dan metode objek saya sering melempar pengecualian ketika terjadi kesalahan.

Melakukan itu, saya:

  • mencapai konsinstensi jenis kembali
  • membuat kode sederhana untuk unit test
  • tidak perlu pemeriksaan bersyarat pada jenis yang dikembalikan

Namun, melemparkan pengecualian dalam plugin WordPress, berarti tidak ada yang akan menangkap mereka, berakhir dengan kesalahan fatal yang sama sekali tidak diinginkan, terutama dalam produksi.

Untuk menghindari masalah ini, saya biasanya memiliki "rutin utama" yang terletak di file plugin utama, yang saya bungkus dalam try/ catchblok. Ini memberi saya kesempatan untuk menangkap pengecualian dalam produksi dan mencegah kesalahan fatal.

Contoh kasar dari kelas:

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

dan menggunakannya dari file plugin utama:

# 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');

Tentu saja, di dunia nyata Anda dapat melempar dan menangkap berbagai jenis pengecualian dan berperilaku berbeda sesuai dengan pengecualian, tetapi ini harus memberi Anda arahan.

Opsi lain yang sering saya gunakan (dan Anda tidak disebutkan) adalah mengembalikan objek yang berisi flag untuk memverifikasi jika tidak ada kesalahan, tetapi menjaga konsistensi jenis kembali.

Ini adalah contoh kasar dari objek seperti itu:

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

Sekarang, dari mana saja di plugin Anda, Anda dapat melakukan:

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

Perhatikan bagaimana di my_plugin_get_options()atas selalu mengembalikan instance Optionskelas, dengan cara ini Anda selalu dapat melewatkan nilai kembali, dan bahkan menyuntikkannya ke objek lain yang menggunakan tip-petunjuk dengan sekarang khawatir bahwa tipenya berbeda.

Jika fungsi telah kembali null/ falsejika terjadi kesalahan, sebelum meneruskannya Anda terpaksa memeriksa apakah nilai yang dikembalikan valid.

Pada saat yang sama, Anda memiliki cara yang jelas untuk memahami ada sesuatu yang salah dengan opsi instance.

Ini adalah solusi yang baik jika kesalahan adalah sesuatu yang dapat dengan mudah dipulihkan, menggunakan default atau apa pun yang cocok.

gmazzap
sumber