Tôi nghĩ rằng không thể đưa ra một câu trả lời dứt khoát ở đây, bởi vì những lựa chọn như thế này là sở thích cá nhân.
Hãy xem xét rằng những gì tiếp theo là cách tiếp cận của tôi , và tôi không có giả định rằng đó là cách tiếp cận đúng .
Điều tôi có thể nói chắc chắn là bạn nên tránh lựa chọn thứ ba của mình:
Chỉ cần trả về null / false
Điều này là xấu dưới khía cạnh khác nhau:
- trả lại loại liên tục
- làm cho các chức năng khó hơn để kiểm tra đơn vị
- buộc kiểm tra có điều kiện về kiểu trả về (
if (! is_null($thing))...
) làm cho mã khó đọc hơn
Tôi, thường xuyên hơn, sử dụng OOP để mã trình cắm và các phương thức đối tượng của tôi thường ném ngoại lệ khi có sự cố.
Làm điều đó, tôi:
- hoàn thành sự đồng thuận
- làm cho mã đơn giản để kiểm tra đơn vị
- không cần kiểm tra có điều kiện về loại trả lại
Tuy nhiên, ném ngoại lệ vào một plugin WordPress, có nghĩa là sẽ không có gì bắt được chúng, kết thúc bằng một lỗi nghiêm trọng hoàn toàn không mong muốn, đặc biệt là trong sản xuất.
Để tránh vấn đề này, tôi thường có một "thói quen chính" nằm trong tệp plugin chính, mà tôi gói trong một khối try
/ catch
. Điều này cho tôi cơ hội để bắt ngoại lệ trong sản xuất và ngăn ngừa lỗi nghiêm trọng.
Một ví dụ sơ bộ của một lớp:
# 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;
}
}
và sử dụng nó từ tệp plugin chính:
# 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');
Tất nhiên, trong thế giới thực, bạn có thể ném và bắt các loại ngoại lệ khác nhau và hành xử khác nhau theo ngoại lệ, nhưng điều này sẽ cho bạn một hướng đi.
Một tùy chọn khác mà tôi thường sử dụng (và bạn không đề cập) là trả về các đối tượng có chứa cờ để xác minh nếu không có lỗi xảy ra, nhưng vẫn giữ tính nhất quán của kiểu trả về.
Đây là một ví dụ sơ bộ về một đối tượng như thế:
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;
}
}
Bây giờ, từ bất kỳ nơi nào trong plugin của bạn, bạn có thể làm:
/**
* @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
}
Lưu ý làm thế nào my_plugin_get_options()
ở trên luôn trả về một thể hiện của Options
lớp, theo cách này, bạn luôn có thể chuyển giá trị trả về xung quanh và thậm chí tiêm nó cho các đối tượng khác sử dụng gợi ý kiểu mà bây giờ lo lắng rằng kiểu này khác.
Nếu hàm đã trả về null
/ false
trong trường hợp có lỗi, trước khi chuyển nó xung quanh bạn đã buộc phải kiểm tra xem giá trị trả về có hợp lệ không.
Đồng thời, bạn có một cách rõ ràng để hiểu là có gì đó không đúng với thể hiện tùy chọn.
Đây là một giải pháp tốt trong trường hợp lỗi là thứ có thể dễ dàng phục hồi, sử dụng mặc định hoặc bất cứ điều gì phù hợp.