【问题标题】:Should a mvc model in php just be a PDO wrapper?php 中的 mvc 模型应该只是 PDO 包装器吗?
【发布时间】:2019-10-15 14:27:33
【问题描述】:

我一直在尝试了解 MVC 模式(没有框架),但是无论我在 Internet 上阅读什么资料,它似乎总是自相矛盾。

我的项目现在包含一个可以提交的表单,以便向数据库添加一个元素。另一个页面只是列出了数据库中的所有元素。

据我了解,我的模型应该连接到数据库(或者只是将连接作为参数,其他我不太清楚的东西)并具有像“saveItem”这样的功能(它将 $_POST 变量作为一个输入并解析它)和“listItems”(它只是将所有条目返回到页面)。

但是,控制器从何而来?现在我在模型中解析我的数据。但是,如果这应该在控制器中完成,那么模型实际上做了什么?我遇到了this 页面。在这里,模型只有像“select”这样的方法,其输入只是一个 sql 查询。但这似乎本质上只是一个 PDO 包装器。 (this 页面中关于 PDO 已经是一种包装器的矛盾信息,实际上没有必要这样做。)

我想这有点道理,如果模型只是作为一个包装器编写,它实际上与我的网站的细节没有任何关系。 (我现在的理解是,mvc 的每个部分对于每个项目都是高度特定的。)

但是,模型或控制器似乎都是不必要的。任何一个模型都会解析数据,控制器什么也不做,反之亦然。

如有任何澄清,我将不胜感激。

【问题讨论】:

  • 应用程序的 domain 部分与 MVC 几乎没有关系。 Model指的是呈现给View的数据封装。 控制器处理请求
  • 您可能想阅读更通用的 MVC 描述。见en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller。一些框架喜欢将模型与您的域紧密耦合,尽管这不一定是通用的
  • 以下资源将使您更好地了解 MVC:this(将其视为一般指南并继续查看/阅读下一个链接)、thisthisthis ,也许this。如有需要,请随时询问。

标签: php oop model-view-controller pdo


【解决方案1】:

我会将此问题视为真正的询问,而不是要求查看来自 Internet 的一些 SEO 垃圾邮件文章。就这样:

首先您需要了解的是,“模型”一词是模棱两可的。它可以代表整个应用程序的业务逻辑,也可以代表您的意思——与数据库交互的一段代码。为了避免这种歧义,让我们坚持前者。它将帮助您与控制器达成和解。而我们将“较小的模型”称为存储。实际与数据库交互的代码的涵盖术语。

我有一个非常简洁的文章,MVC in simpler terms or the structure of a modern web-application。它将帮助您全面了解 MVC。

现在离你的问题更近了。

无论在何种意义上,数据库包装器都不能被视为模型。数据库包装器是存储类使用的服务。因此,您的应用程序中至少可以有 3 层:

  • 控制器。只是将 HTTP 客户端的请求传递给业务模型的接口
  • 服务或助手。通常(并且错误地)写在控制器中的代码。例如,如果您需要注册用户,则在控制器中,您从用户服务调用方法,前提是数据来自客户端。
  • 一个存储类。与数据库交互的实际代码。例如,它可能是一个 User 类,其中包含诸如 register 之类的方法。此类将使用 PDO(或更高级的包装器,或 ORM 实例)作为类变量。

后两者实际上应该封装整个应用程序的业务逻辑。

这里最棘手的部分是 Storage 类的实例化。鉴于连接只能完成一次,应该有办法实例化 UserStorage 对象,为它提供数据库连接。这是通过依赖注入容器解决的稍微不同的问题

用一点代码来说明上面的内容

class UserController extends Controller
{
    public function create($request)
    {
        $userService = $this->serviceContainer->get('user_service');
        $userService->create(
            $request->email;
            $request->password;
        );
    }
}
class UserService
{
    public function create($username, $password)
    {
        // here, userStorage instance was already injected 
        // in the UserService in the controller by DI container
        $this->userStorage->create(
            $request->email;
            $request->password;
        );
    }
}
class UserStorage
{
    public function create($username, $password)
    {
        $sql = "INSERT INTO user VALUES (null, ?, ?)";
        // here, db instance was already injected 
        // in the UserStorage in the controller by DI container
        $this->db->prepare($sql)->execute([$username, $password]);
    }
}

所有这些看似重复的内容可能被认为是不必要的冗长,但这是有原因的:

  1. 在实际代码中,每个阶段还有其他部分,例如,
    • Controller 会验证提交的表单(例如表单是否实际提交,密码是否相等等)并调用 View 来呈现表单。
    • UserService 可以执行其他验证,例如此类电子邮件是否已存在
  2. 不同的呼叫点
    • UserService 可以从许多不同的地方调用:从上述控制器或命令行实用程序或 REST 控制器。
    • 可以从更多地方调用 UserStorage。比如有一个TaskService,它列出了属于用户的任务,它自然会很好地利用UserStorage类。等等。

因此,以这种方式分隔图层非常有意义。

当然,这只是一个过于简化的草稿模型,它没有实现通常在这里的 ORM 以及许多其他东西。但草图越简单,细节越少,就越容易理解主要思想。

【讨论】:

  • 我建议使用data mapper 术语,而不是repository。数据映射器应该是接受数据库连接(PDO 实例)并直接与数据库通信(通过其 API)的一个组件。
  • @dakis 数据映射器的术语过于狭窄和具体。它只是可能的 ORM 变体之一,ORM 也不是一个好的替代品。不管你是对的,存储库都是一样的误导。我将其更改为更合适的术语
  • 我明白了。我不知道这个特定的 ORM 和数据映射器情况。感谢您灵活选择更合适的术语。
【解决方案2】:

我看到了这个页面。在这里,模型只有像“select”这样的方法,其输入只是一个 sql 查询。但这似乎本质上只是一个 PDO 包装器。

你是对的。事实上,这个例子结构很差,不符合任何合理的 MVC 设计概念。我建议您完全忽略它并寻找更好的示例。

  • 此示例中的DB 类(据称是“模型”)是一个数据库助手类。虽然这是一个有用的东西,但它在任何意义上都不是 MVC 模型,而且这个模型也不是特别好。

  • Users 类(据称是“控制器”)不是控制器。它实际上更类似于模型,因为它试图(尴尬地)将业务对象表示为一个类。

    (顺便说一句,扩展数据库助手类是一种设计“气味”,应该避免——这意味着每个实例化的对象都将创建自己的与数据库的单独连接。)

  • list.php 文件(据称是“视图”)也不是什么好视图。虽然它提供了一些演示功能,但它还通过对模型进行操作来扮演控制器的角色。在大多数 MVC 应用程序中,视图被实现为纯模板文件——通常甚至不是可执行代码——由控制器传递数据。

现在我们已经正确地分解了这个糟糕的教程:

MVC 应用程序中的一个常见架构是the active record pattern,其中数据库中的每个表(除了纯粹的关系表)都由一个类表示,您的应用程序加载的这些表中的每一行都由一个类表示该类的实例,并且每个实例都有可用于操作该行内容的方法。

实现这样的架构通常需要某种形式的数据库映射器或 ORM 框架。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-07-17
    • 1970-01-01
    • 2013-03-14
    • 1970-01-01
    • 2020-07-04
    • 1970-01-01
    • 2019-05-31
    • 1970-01-01
    相关资源
    最近更新 更多