我是否在 Laravel 控制器中使用静态方法将自己设置为失败?

Am I setting myself up for failure using a static method in a Laravel Controller?

我对 OOP 很陌生,所以这确实是一个基本的 OOP 问题,在 Laravel 控制器的上下文中。

我正在尝试创建一个通知系统系统,当某些其他对象被创建、编辑、删除等时,它会创建 Notification 对象。因此,例如,如果 User 被编辑,然后我想生成关于此编辑的 Notification。按照这个例子,我创建了 UserObserver,它在保存 User 时调用 NotificationController::store()

class UserObserver extends BaseObserver
{
    public function saved($user)
    {
        $data = [
            // omitted from example
        ];

        NotificationController::store($data);
    }
}

为了完成这项工作,我必须将 NotificationController::store() 设为静态。

class NotificationController extends \BaseController {
public static function store($data)
{
    // validation omitted from example

    $notification = Notification::create($data);
}

我对 static 的含义只是模糊地了解,所以我在这里所做的事情很可能存在内在错误,但这似乎或多或少地完成了工作。但是,我读过的所有内容都表明静态函数 通常 不好的做法。我在这里做的是 "wrong," 吗?我怎样才能做得更好?

我将有几个其他观察者 类 需要调用相同的 NotificationController::store(),并且我希望 NotificationController::store() 处理 $data 的任何验证。

我刚刚开始学习单元测试。我在这里所做的会不会对测试造成任何困难?

我在这里广泛地写了关于静力学的文章:How Not To Kill Your Testability Using Statics。适用于您的情况的要点如下:

静态函数调用 couple 代码。无论出于何种原因,都不可能 用其他任何东西替换 静态函数调用或 跳过 这些调用。 NotificationController::store() 本质上与 substr() 属于相同的 class 事物。现在,您可能不想用其他任何东西替换对 substr 的调用;但是有很多原因让您现在或以后可能想要替换 NotificationController

单元测试只是一个非常明显的用例,其中非常需要替换。如果你想单独测试 UserObserver::saved 函数,因为它包含一个复杂的算法,你需要用所有可能的输入来测试它以确保它正常工作,你不能将该算法与对 [=12= 的调用分离].而该函数可能会依次调用一些 Model::save() 方法,该方法又想与数据库对话。您需要设置所有其他不相关代码所需的整个环境(并且可能包含也可能不包含其自身的错误),基本上不可能单独测试这个功能。

如果您的代码看起来更像这样:

class UserObserver extends BaseObserver
{
    public function saved($user)
    {
        $data = [
            // omitted from example
        ];

        $this->NotificationController->store($data);
    }
}

好吧,$this->NotificationController 显然是一个可以在某些时候被替换的变量。大多数情况下,该对象会在您实例化 class:

时注入
new UserObserver($notificationController)

您可以简单地注入一个允许调用任何方法的模拟对象,但它什么也不做。然后您可以单独测试 UserObserver::saved() 并确保它实际上没有错误。

一般来说,使用依赖注入代码可以使您的应用程序更加灵活,并允许您将其拆分。这对于单元测试是必要的,但在以后你现在甚至无法想象的场景中也会派上用场,但是从现在开始半年后你会被难住,因为你需要为你想要的一些新功能重构你的应用程序实施。

警告:我从未写过一行 Laravel 代码,但据我所知,它 确实 支持某种形式的依赖注入。如果确实如此,您绝对应该使用该功能。否则,请非常清楚您的代码的哪些部分与其他部分耦合,以及这将如何影响您以后将其拆分和重构的能力。