如何在 PHP 中的模型之间传递数据映射器


how to pass data mapper between models in php

在过去的几天里,我读了很多关于域对象、数据映射器和其他一些我不知道的东西。我决定尝试在我正在编写的一些代码中实现这一点(部分是为了学习目的,部分是因为我想创建一个真正简化的框架来快速构建一些项目......使用我可以轻松理解和修改的代码)。

在阅读了这篇文章和这篇文章之后,我计划创建一个 SINGLE 数据映射器,并连接到其中的数据库,然后使用工厂将数据映射器传递到每个域对象(嗯,需要它的对象)。我在下面包含一些示例代码

class data_mapper {
    private $dbh;
    function __construct() 
    {
        $this->dbh = new PDO(DB_STRING, DB_USER, DB_PASS);
    }
    public function createUser($data) ...
    public function updateUser($user_id, $data) ...
    public function createCategory($data) ...
}
class user {
    private $data_mapper;
    public $user_id;
    public $data;
    function __construct($dm) 
    {
        $this->data_mapper = $dm;
    }
    function someFunction() {
        /* some code */
        $this->data_mapper->updateUser($user_id, $data);
        /* some more code */
    }
}
class factory {    
    private $data_mapper = null;
    function __construct($dm) 
    {
        $this->data_mapper = $dm;
    }
    public function create($name)
    {
        return new $name($this->data_mapper);
    }
}
/* USAGE */
$dm = new data_mapper();
$factory = new factory($dm);
$user = $factory->create('user');

我有两个问题:

  1. 我最近看过的许多示例为每个模型创建了不同的data_mapper。我应该这样做吗?如果我这样做,这不会使工厂变得更加复杂(即我需要创建单个PDO对象并将其传递给每个数据映射器,然后将正确的数据映射器传递到每个模型中)?

  2. 如果我上面的代码暴露了对模型、数据映射器或其他任何东西的理解方面的一些缺陷,请启发我(我知道这不是一个真正的问题)......

我所知,"数据映射器"模式在现代框架中以原型模型类的形式实现,所有应用程序模型都是从中继承的。

在这个原型模型中,您可以实现 CRUD 方法,因此您的模型将拥有它。

说到传递 pdo,当地学者会告诉你,你应该将 PDO 对象作为构造函数参数传递。但是,如果您看一下任何现代框架 - 他们正在使用某种包含PDO实例的单例

所以,你想要一个真正简化的PHP框架。数据映射器听起来像是过度工程。

多年来,我用PHP制作了一些KISS框架,这就是我所做的:

  • 使用模板(又名视图),例如 Smarty。非常适合外包您的网页设计。
  • 创建一个名为页面的文件夹(又名控制器)。页面仅按索引调用.php。
  • 创建一个名为 models 的文件夹。只有模型与您的数据库通信。
  • 创建索引.php(又名路由器)。具有?page=dog参数。

严格的MCV(又名MVC)术语不是圣杯,以上是简单网站/应用程序/CMS的一个很好的实现。

零件

/

pages/page_dog.inc.php页面加载他需要的模型,操作并显示它:

<?php if(!defined('YOURFRAMEWORK')){die('External access denied');}
// Page init
require './models/model_dog.inc.php';
$id = $_GET['id']; // todo fix injection attacks
$ModelDog = new ModelDog($DB);
// Page main
$ModelDog->Load($id);
echo $ModelDog->item['breed'];

对于列表(用户选择$id的页面),您可能不希望单独的模型代表每个结果。改为创建一个列表类,与模型非常相似,但在一个数组中返回多个项目。它很诱人地DRY并使ListerDog类使用ModelDog,但没有可读性增益,只是性能痛苦。

/index.php(又名路由器)在身份验证和初始化($DB)之后调用页面(通过require_once()):

<?php
define('YOURFRAMEWORK', 1); // disable "External access denied" error.
require_once('config.inc.php'); // todo have this hold the $config[] array.
$DB = @new mysqli( // or your derative, so you can log each query() call.
  $config['db']['host'],
  $config['db']['user'],
  $config['db']['pasw'],
  $config['db']['database']
);
if ($DB->connect_error) { die('db error: ' . mysqli_connect_errno()); }
// Load page requested by user. For now, its dog hardcoded.
require_once('./pages/page_dog.inc.php');
$DB->close;
/

models/model_dog.inc.php(又名模型)为您与数据库通信,处理和清理数据。我也使用这个放置表单处理函数。

<?php if(!defined('YOURFRAMEWORK')){die('External access denied');}
class ModelDog extends BaseModel {
  private $tablename = 'dogs';
  /**
   * Load last (or specific) item.
   * @param integer $id
   * @return boolean Returns false when failed.
   */
  public function Load($id=null) {
    $query = "SELECT * FROM `".$this->tablename."` WHERE `id`='".$this->DB->Sanitize($id)."';";
    // TODO ..  $this->item =
  }
  public function ItemDefaults() {
    return array(
      'id' => 0,
      'breed' => 'unknown',
      'height' => 0
    );
  }
  // TODO ..
}
/

models/basemodel.inc.php 从常见的内容扩展每个模型类,如下所示:

abstract class BaseModel
{
  protected $item = array(); // Here is all the data!
  protected $DB = null;
  public function __construct($aQDB) {
    parent::__construct();
    $this->DB = $aDB;
    $this->Reset();
  }
  public function Reset() {
    $this->item = ItemDefaults();
  }
  public function Item() { return $item; }
  // As seen in dog
  abstract public function Load($id);
  abstract public function ItemDefaults();
  // But descendants (models) must also implement:     
  abstract public function Save($id = NULL);
  abstract public function Delete($id);
  // You may want to add Validate() and other internal things here.
}

以上所有内容都是我在需要另一个小框架时自己构建的最低限度版本。在适当的子类化中,你会得到更多的收益,而不是让更多的类做更多的事情。一个网站本质上是一件简单的事情,直到它过于复杂。

要点/TLDR;

如果你真的想要一个真正简化的PHP框架,不要读太多。只需编写代码,您就会发现它需要什么才能让您更好地工作。