PHP面向对象之领域模型+数据映射器实例(分析)


Posted in PHP onJune 21, 2017

这里要说明一下 因为本人比较懒 博客中相关文章的内容更多的是对<深入PHP面向对象、模式与实践>一书中代码的整理和简单注解方便自己日后复习和参考,

对相关内容感兴趣的初学的朋友建议请先阅读原文。此处的内容只能当成一种学习的补充和参考。谢谢!

因原书中领域模型+数据映射器的示例代码是连贯在一起的 所以这里就整理在一起了。

简单介绍一下我的看法,从数据库操作的角度看领域模型主要是操作数据表中的单条记录的而数据映射器是操作整个数据表的数据的。

按原文的解释数据映射器是一个负责将数据库数据映射到对象的类,而领域模型象征着真实世界里项目中的各个参与者,它在数据中通常表现为一条记录。

废话不多说,代码和注解如下:

与领域模型相关的三个数据表结构分别为venue(场所)、space(空间)、event(事件)。

create table 'venue' (
   'id' int(11) not null auto_increment,
   'name' text,
   primary key ('id')
)
create table 'space' (
   'id' int(11) not null auto_increment,
   'venue' int(11) default null,
   'name' text,
   primary key ('id')
)
create table 'event' (
   'id' int(11) not null auto_increment,
   'space' int(11) default null,
   'start' mediumtext,
   'duration' int(11) default null,
   'name' text,
   primary key ('id')
)
//领域模型(这里只建了一个Venue类用于理解)
namespace woo\domain;

abstract class DomainObject{      //抽象基类
  
  private $id;
  
  function __construct ($id=null){
    $this->id = $id;
  }
  
  function getId(){
    return $this->id;
  }
  
  //原书没有具体实现,应该是用于获取对象的从属对象的,比如venue(场所)相关的space(空间)对象
  //具体的代码实现中应该从数据库中查询了相关数据并调用了Collection类,下面看到这个类的时候会有一个了解
  //而且这个方法的实现应该放在子类中才对
  static function getCollection($type){   
    return array();
  }
  
  function collection(){
    return self::getCollection(get_class($this));
  }
  
}

class Venue extends DomainObject {
  private $name;
  private $spaces;
  
  function __construct ($id = null,$name=null){
    $this->name= $name;
    $this->spaces = self::getCollection('\\woo\\domain\\space'); //这里应该证明了我上述的猜测
    parent::__construct($id);
  }
  
  function setSpaces(SpaceCollection $spaces){
    $this->spaces = $spaces;
  }
  
  function addSpace(Space $space){
    $this->spaces->add($space);
    $space->setVenue($this);
  }
  
  function setName($name_s){
    $this->name = $name_s;
    $this->markDirty();
  }
  
  function getName(){
    return $this->name;
  }
}


//数据映射器(正如原文的解释数据映射器是一个负责将数据库数据映射到对象的类)
namespace woo\mapper;

abstract class Mapper{      //抽象基类
  abstract static $PDO;    //操作数据库的pdo对象
  function __construct (){
    if(!isset(self::$PDO){
      $dsn = \woo\base\ApplicationRegistry::getDSN();
      if(is_null($dsn)){
        throw new \woo\base\AppException("no dns");
      }
      self::$PDO = new \PDO($dsn);
      self::$PDO->setAttribute(\PDO::ATTR_ERRMODE,\PDO::ERRMODE_EXCEPTION);
    }
  }
  
  function createObject($array){          //将数组创建为上述领域模型中的对象
    $obj = $this->doCreateObject($array);    //在子类中实现
    return $obj;
  }
  
  function find($id){                //通过ID从数据库中获取一条数据并创建为对象
    $this->selectStmt()->execute(array($id));
    $array= $this->selectStmt()->fetch();
    $this->selectStmt()->closeCursor();
    if(!is_array($array)){
      return null;
    }
    if(!isset($array['id'])){
      return null;
    }
    $object = $this->createObject($array);
    return $object;  
  }
  
  function insert(\woo\domain\DomainObject $obj){      //将对象数据插入数据库
    $this->doInsert($obj);
  }
  
  //需要在子类中实现的各抽象方法
  abstract function update(\woo\domain\DomainObject $objet);
  protected abstract function doCreateObject(array $array);
  protected abstract function selectStmt();
  protected abstract function doInsert(\woo\domain\DomainObject $object);
}

//这里只建立一个VenueMapper类用于理解
class VenueMapper extends Mapper {
  function __construct (){    
    parent::__construct();  //各种sql语句对象  
    $this->selectStmt = self::$PDO->prepare("select * from venue where id=?");
    $this->updateStmt = self::$PDO->prepare("update venue set name=?,id=? where id=?");
    $this->insertStmt = self::$PDO->prepare("insert into venue (name) values(?)");
  }
  
  protected function getCollection(array $raw){    //将Space数组转换成对象
    return new SpaceCollection($raw,$this);      //这个类的基类在下面    
  }
  
  protected function doCreateObject (array $array){  //创建对象
    $obj = new \woo\domain\Venue($array['id']);
    $obj->setname($array['name']);
    return $obj;
  }
  
  protected function doInsert(\woo\domain\DomainObject $object){ //将对象插入数据库
    print 'inserting';
    debug_print_backtrace();
    $values = array($object->getName());
    $this->insertStmt->execute($values);
    $id = self::$PDO->lastInsertId();
    $object->setId($id);
  }
  
  function update(\woo\domain\DomainObject $object){    //修改数据库数据
    print "updation\n";
    $values = array($object->getName(),$object->getId(),$object->getId());
    $this->updateStmt->execute($values);
  }
  
  function selectStmt(){          //返回一个sql语句对象
    return $this->selectStmt;
  }
  
}

Iterator接口定义的方法:

rewind()            指向列表开头   
current()            返回当前指针处的元素
key()                返回当前的键(比如,指针的指)
next()               
valid()

下面这个类是处理多行记录的,传递数据库中取出的原始数据和映射器进去,然后通过数据映射器在获取数据时将其创建成对象

abstract class Collection implements \Iterator{
  protected $mapper;      //数据映射器
  protected $total = 0;    //集合元素总数量
  protected $raw = array();  //原始数据
  
  private $result;
  private $pointer = 0;    //指针
  private $objects = array();  //对象集合
  
  function __construct (array $raw = null,Mapper $mapper= null){
    if(!is_null($raw)&& !is_null($mapper)){
      $this->raw = $raw;
      $this->total = count($raw);
    }
    $this->mapper = $mapper;
  }
  
  function add(\woo\domain\DmainObject $object){  //这里是直接添加对象
    $class = $this->targetClass();
    if(!($object instanceof $class)){
      throw new Exception("This is a {$class} collection");
    }
    $this->notifyAccess();
    $this->objects[$this->total] = $object;
    $this->total ++;
  }
  
  abstract function targetClass();  //子类中实现用来在插入对象时检查类型的
  
  protected function notifyAccess(){  //不知道干嘛的
    
  }
  
  private function getRow($num){    //获取集合中的单条数据,就是这里通过数据映射器将数据创建成对象
    $this->notifyAccess();
    if($num >= $this->total || $num < 0){
      return null;
    }
    if(isset($this->objects[$num]){
      return $this->objects[$num];
    }
    if(isset($this->raw[$num]){
      $this->objects[$num] = $this->mapper->createObject($this->raw[$num]);
      return $this->objects[$num];
    }
  }
  
  public function rewind(){      //重置指针
    $this->pointer = 0;
  }
  
  public function current(){      //获取当前指针对象
    return $this->getRow($this->pointer);
  }
  
  public function key(){        //获取当前指针
    return $this->pointer;
  }
  
  public function next(){      //获取当前指针对象,并将指针下移  
    $row = $this->getRow($this->pointer);
    if($row){$this->pointer ++}
    return $row;
  }
  
  public function valid(){    //验证
    return (!is_null($this->current()));
  }
  
}

//子类
class VenueColletion extends Collection implements \woo\domain\VenueCollection{
  function targetClass(){
    return "\woo\domain\Venue";
  }
}


//客户端
$mapper = new \woo\mapper\VenueMapper();
$venue = $mapper->find(12);
print_r($venue);

$venue = new \woo\domain\Venue();
$venue->setName("the likey lounge-yy");
//插入对象到数据库
$mapper->insert($venue);
//从数据库中读出刚才插入的对象
$venue = $mapper->find($venue->getId());
print_r($venue);

//修改对象
$venue->setName("the bibble beer likey lounge-yy");
//调用update来更新记录
$mapper->update($venue);
//再次读出对象数据
$venue = $mapper->find($venue->getId());
print_r($venue);


//结束

以上这篇PHP面向对象之领域模型+数据映射器实例(分析)就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

PHP 相关文章推荐
实用函数2
Nov 08 PHP
如何解决CI框架的Disallowed Key Characters错误提示
Jul 05 PHP
php中过滤非法字符的具体实现
Oct 29 PHP
页面利用渐进式JPEG来提升用户体验度
Dec 01 PHP
PHP动态规划解决0-1背包问题实例分析
Mar 23 PHP
Laravel 5框架学习之子视图和表单复用
Apr 09 PHP
php判断当前操作系统类型
Oct 28 PHP
CodeIgniter表单验证方法实例详解
Mar 03 PHP
PHP屏蔽关键字实现方法
Nov 17 PHP
PHP性能分析工具xhprof的安装使用与注意事项
Dec 19 PHP
PHP程序守护进程化实现方法详解
Jul 16 PHP
PHP获取php,mysql,apche的版本信息及更多服务器信息
Mar 09 PHP
PHP基于PDO实现的SQLite操作类【包含增删改查及事务等操作】
Jun 21 #PHP
老生常谈PHP面向对象之标识映射
Jun 21 #PHP
PHP封装的PDO数据库操作类实例
Jun 21 #PHP
PHP基于ORM方式操作MySQL数据库实例
Jun 21 #PHP
php 猴子摘桃的算法
Jun 20 #PHP
详解php框架Yaf路由重写
Jun 20 #PHP
PHP简单计算两个时间差的方法示例
Jun 20 #PHP
You might like
php Smarty初体验二 获取配置信息
2011/08/08 PHP
php判断并删除空目录及空子目录的方法
2015/02/11 PHP
php计算两个文件相对路径的方法
2015/03/14 PHP
php合并数组并保留键值的实现方法
2018/03/12 PHP
php实现微信支付之企业付款
2018/05/30 PHP
Thinkphp页面跳转设置跳转等待时间的操作
2019/10/16 PHP
php操作redis数据库常见方法实例总结
2020/02/20 PHP
javascript IE中的DOM ready应用技巧
2008/07/23 Javascript
JQuery为textarea添加maxlength属性的代码
2010/04/07 Javascript
js 实现复制到粘贴板的功能代码
2010/05/13 Javascript
js判断IE6/IE7/FF的代码[XMLHttpRequest]
2011/02/16 Javascript
JavaScript更改字符串的大小写
2015/05/07 Javascript
XML文件转化成NSData对象的方法
2015/08/12 Javascript
几种经典排序算法的JS实现方法
2016/03/25 Javascript
js调用屏幕宽度的简单方法
2016/11/14 Javascript
js清除浏览器缓存的几种方法
2017/03/15 Javascript
基于node打包可执行文件工具_Pkg使用心得分享
2018/01/24 Javascript
[56:18]DOTA2上海特级锦标赛主赛事日 - 4 败者组第四轮#2 MVP.Phx VS Fnatic第二局
2016/03/05 DOTA
Python获取脚本所在目录的正确方法
2014/04/15 Python
Python获取CPU、内存使用率以及网络使用状态代码
2018/02/08 Python
python3 unicode列表转换为中文的实例
2018/10/26 Python
Python中常用的内置方法
2019/01/28 Python
python assert的用处示例详解
2019/04/01 Python
Python 实现输入任意多个数,并计算其平均值的例子
2019/07/16 Python
用python爬取历史天气数据的方法示例
2019/12/30 Python
Python正则表达式高级使用方法汇总
2020/06/18 Python
python获得命令行输入的参数的两种方式
2020/11/02 Python
Woolworth官网:澳洲第一大超市
2017/06/25 全球购物
Linux的文件类型
2016/07/05 面试题
客服工作职责
2013/12/11 职场文书
洗煤厂厂长岗位职责
2014/01/03 职场文书
校长就职演讲稿
2014/01/06 职场文书
篮球友谊赛通讯稿
2014/10/10 职场文书
大国崛起英国观后感
2015/06/02 职场文书
赢在中国观后感
2015/06/02 职场文书
Angular CLI发布路径的配置项浅析
2021/03/29 Javascript