最近几天,我在PHP中广泛阅读有关OOP和MVC的书籍和网页,这样我才能成为更好的程序员。我对MVC的理解遇到了一些问题:
我在哪里放mysql_query
?
我应该将它放在控制器中并在基于提供的查询返回数据的模型上调用方法吗?或者我应该把它放在模型本身?我提供的垃圾都是两种选择吗?
答案 0 :(得分:15)
你可能已经列出了你正在阅读的书籍,因为大多数(如果不是全部)涉及MVC的书籍都是错误的。
如果您想成为更好的开发者,我建议您先从Marting Fowler的文章开始 - GUI Architectures。其次是同一本书的作者 - "Patterns of Enterprise Application Architecture"。然后,下一步将是您研究SOLID principles并了解如何编写Law of Demeter之后的代码。这应该涵盖基础=]
不是真的。至少不是经典的MVC,因为它是defined for Smalltalk。
而在PHP中,您有另外4个针对相同目标的模式:MVC Model2,MVP,MVVM和HMVC。再说一遍,我懒得再一次写下差异,所以我只想链接到我的old comment。
首先要注意的是MVC中的Model不是类或对象。它是一个包含多个类的层。基本上模型层是所有层组合的(但是,第二层应该称为“域对象层”,因为它包含“域模型对象”)。如果您想阅读有关模型图层各部分所包含内容的快速摘要,可以尝试阅读this old comment(跳至“侧边注释”部分)。
该图片来自Fowler网站上的Service Layer文章。
Controller在MVC中有一个主要职责(我将在这里讨论Model2实现):
从模型层(服务或域对象)对结构执行命令,这些命令会更改所述结构的状态。
它通常具有次要责任:将结构从模型层绑定(或以其他方式传递)到视图,但如果您遵循SRP
,它就会成为一种可疑的做法信息的存储和检索在数据源层处理,通常实现为DataMapper(不要与滥用该名称的ORM混淆)。
以下是对它的简化使用方式:
$mapper = $this->mapperFactory->build(Model\Mappers\User::class);
$user = $this->entityFactory->build(Model\Entities\User::class);
$user->setId(42);
$mapper->fetch($user);
if ($user->isBanned() && $user->hasBannExpired()){
$user->setStatus(Model\Mappers\User::STATUS_ACTIVE);
}
$mapper->store($user);
如您所见,域对象甚至不知道存储了来自它的信息。并且它都没有关于您放置数据的位置。它可以存储在MySQL或PostgreSQL或某些noSQL数据库中。或者可能推送到远程REST API。或者也许映射器是用于测试的模拟器。要替换映射器,您需要做的就是为此方法提供不同的工厂。
答案 1 :(得分:7)
模型和实体类表示应用程序的数据和逻辑,许多人称之为业务逻辑。通常,它负责:
这是MVC序列图,显示了http请求期间的流程:
在这种情况下,Model是实现访问数据库的代码的最佳位置。
答案 2 :(得分:2)
首先,不要使用mysql_query()
和家人;他们被弃用了,所以还要考虑学习PDO和/或mysqli。
该模型负责数据处理;它为控制器提供了一个接口,用于检索和/或存储信息。因此,这将是数据库操作发生的主要场所。
<强>更新强>
回答OP在评论中提出的问题:“整个数据库的一个通用模型或每个表/操作的模型?”
模型旨在抽象出各个表(尽管有些模型专门处理单个表);例如,不是要求所有文章然后查询作者的用户名,而是有一个这样的函数:
function getArticles()
{
// query article table and join with user table to get username
}
您将创建多少个模型很大程度上取决于项目的大小以及数据的相互关联程度。如果您可以识别独立的数据组,则可能需要为每个组创建模型;但这并不困难。快速统治。
数据操作可以是同一模型的一部分,除非您希望在只读模型和只写模型之间进行明确分离(我不知道这种情况需要保证,但谁知道)。
答案 3 :(得分:2)
模型包含表示应用程序状态的域对象或数据结构。 [wikipedia]。因此,该模型将成为进行数据库调用的地方。
在'经典'(没有更好的单词atm)MVC模式中,视图将从模型中获得当前状态。
不要错误地说模型是用于访问数据库。它不仅仅是访问数据库。
答案 4 :(得分:1)
更进一步,您的模型不应包含数据库访问代码。这属于Model / View / Controller之外的另一个层:这称为持久层,可以使用Object-Relational Mapper来实现,例如PHP的流行Doctrine 2。
这样,你永远不会触及任何(我的)SQL代码。持久层为您解决了这个问题。 我真的建议你看一下Doctrine教程,这是一种非常专业的创建应用程序的方法。
您可以创建保存数据的对象以及与之关联的行为,而不是使用从数据库加载的原始数据。
例如,您可能有一个User
类,例如:
class User
{
protected $id;
protected $name;
protected $privileges;
public function setName($name) { ... }
public function getName() { ... }
public function addPrivilege(Privilege $privilege) { ... }
public function getPrivileges() { ... }
}
您的控制器只会与对象进行交互:
class UserController
{
public function testAction()
{
// ...
$user = $em->getRepository('User')->find(123); // load User with id 123
$user->setName('John'); // work with your objects,
echo $user->getName(); // and don't worry about the db!
$em->flush(); // persist your changes
}
}
在幕后,ORM负责发布SELECT
查询,实例化对象,检测对象的修改以及发出必要的UPDATE
语句的所有低级工作! / p>