有人可以帮助我吗?我有以下类(所有功能,为了易读性在这里缩写):
class Database {
private $host = DB_HOST;
// etc...
public function __construct() {
$dsn = 'mysql:host=' . $this->host . ';dbname=' . $this->dbname;
$options = array(PDO::ATTR_PERSISTENT => true, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION);
try {
$this->dbh = new PDO($dsn, $this->user, $this->pass, $options);
} catch (PDOException $e) {
$this->error = $e->getMessage();
echo $this->error;
}
}
public function beginTransaction() {
$this->stmt = $this->dbh->beginTransaction();
}
还有一个关于书籍的课程
class Books extends Controller {
public function __construct() {
$this->model = $this->loadModel('BookModel');
}
// etc.
$this->model->beginTransaction();
BookModel看起来像:
class BookModel {
protected $db;
public function __construct() {
$this->db = new Database;
}
public function beginTransaction() {
$this->db->beginTransaction();
}
我知道我只能访问Database类内部的PDO beginTransaction,但是否有其他方法,或者我必须使用这个复杂的路径,调用调用PDO方法的方法?
我感觉我在做一些非常愚蠢的事情,也许是将BookModel扩展到Database类,但这感觉也不对。
谢谢!
1条答案
按热度按时间aydmsdu91#
一些建议:
[a]不应该在类方法内部创建对象(带 “new”),而应该将已有的示例注入到构造函数/setter中。这被称为依赖注入,可以通过依赖注入容器来应用。
[B]正如@YourCommonSense所指出的,
Database
将极大地受益于构造函数中注入的单个PDO示例。注入任务将是DI容器的工作。例如,如果您使用PHP-DI,则会有一个定义条目用于创建数据库连接:另一个definition条目将其注入
Database
:Database
构造器看起来像:[c]模型不是类(如
BookModel
),而是一个层(模型层,或domain model),由多个组件组成:实体(或域对象**)、value objects、data mappers、repositories、域服务。您的BookModel
至少是实体和数据Map器的组合。注意:从Database
继承它是错误的,因为模型不能是数据库。[d]你不应该将模型注入到控制器中。相反,控制器应该使用所谓的application services(也叫用例,或动作,或交互器),这些服务包含了所谓的应用逻辑,是表现层解耦的正确方式(或交付机制)-其中包括控制器和视图等组件-从域模型。应用程序服务还确保两层之间的通信。注意:还可以存在特定于域并且与特定于应用的应用服务分离的域服务。
[e]
Database
类根本不需要!你已经有了非常优雅和强大的PDO来处理数据库操作。[f]实际上,“call the method that calls the method that calls the PDO method” 并没有错。这个链中的每个方法都封装了特定于当前对象的特定行为。不过,每个方法的功能应该增加一些附加值。否则,拥有这个链就没有意义了。举个例子:在应用服务中,可以直接使用数据Map器从数据库中按id取书:
现在,您可以使用repository来隐藏查询数据来自数据库的事实。(这里是
Book
),因此,其他组件认为存储库是书籍的集合,而不是某个数据库中的一堆数据,然后他们向仓库请求相应的数据。仓库将依次询问数据Map器以查询数据库。因此,前面的代码变为:**[g]**一个“真实的的”错误是将一个对象传递给其他对象,只是为了被最后一个对象使用。
备选示例代码:
我写了一些代码作为你的代码的替代。我希望它能帮助你更好地理解,基于MVC的应用程序的组件如何协同工作。
重要信息:注意命名空间
SampleMvc/Domain/Model/
:即域模型。请注意,应用程序服务(例如,来自SampleMvc/App/Service/
的所有组件)应仅与域模型组件(例如,来自SampleMvc/Domain/Model/
的组件)通信(主要是接口),而不是来自SampleMvc/Domain/Infrastructure/
。反过来,您选择的DI容器将负责为应用程序服务使用的SampleMvc/Domain/Model/
接口注入来自SampleMvc/Domain/Infrastructure/
的适当类实现。请注意
SampleMvc/Domain/Infrastructure/Book/PdoBookMapper.php
中的方法updateBook()
。我在其中包含了一个交易代码,沿着两个很棒的链接。祝您玩得开心。项目结构:
让我们假设以下路由的定义(可能在“routes.php”文件中找到):
应用程序的所有对象都应该由依赖注入容器创建。
但是,如果没有它,创建和调用控制器和/或视图的代码可能看起来像这样:
执行“POST”请求添加图书时,文件“index.php”:
文件“index.php”以防执行“GET”请求查找图书列表:
SampleMvc/App/Controller/Book/AddBook.php:
SampleMvc/App/View/View.php:
SampleMvc/App/View/Book/AddBook.php:
SampleMvc/App/View/Book/FindBooks.php:
SampleMvc/App/Service/Book/AddBook.php:
SampleMvc/App/Service/Book/FindBooks.php:
SampleMvc/App/Service/Book/Exception/BookAlreadyExists.php:
SampleMvc/Domain/Infrastructure/Book/PdoBookMapper.php:
SampleMvc/Domain/Model/Book/Book.php:
SampleMvc/Domain/Model/Book/BookMapper.php: