我会将此问题视为真正的询问,而不是要求查看来自 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]);
}
}
所有这些看似重复的内容可能被认为是不必要的冗长,但这是有原因的:
- 在实际代码中,每个阶段还有其他部分,例如,
- Controller 会验证提交的表单(例如表单是否实际提交,密码是否相等等)并调用 View 来呈现表单。
- UserService 可以执行其他验证,例如此类电子邮件是否已存在
- 不同的呼叫点
- UserService 可以从许多不同的地方调用:从上述控制器或命令行实用程序或 REST 控制器。
- 可以从更多地方调用 UserStorage。比如有一个TaskService,它列出了属于用户的任务,它自然会很好地利用UserStorage类。等等。
因此,以这种方式分隔图层非常有意义。
当然,这只是一个过于简化的草稿模型,它没有实现通常在这里的 ORM 以及许多其他东西。但草图越简单,细节越少,就越容易理解主要思想。