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 相关文章推荐
js下函数般调用正则的方法附代码
Jun 22 PHP
PHP 无限分类三种方式 非函数的递归调用!
Aug 26 PHP
PHP中如何调用webservice的实例参考
Apr 25 PHP
使用php将某个目录下面的所有文件罗列出来的方法详解
Jun 21 PHP
php 模拟post_验证页面的返回状态(实例讲解)
Oct 28 PHP
从零开始学YII2框架(二)通过 Composer 安装扩展插件
Aug 20 PHP
php单例模式实现方法分析
Mar 14 PHP
php异常处理方法实例汇总
Jun 24 PHP
学习PHP的数组总结【经验】
May 05 PHP
详解PHP原生DOM对象操作XML的方法
Oct 17 PHP
PHP获取页面执行时间的方法(推荐)
Dec 10 PHP
php设计模式之策略模式实例分析【星际争霸游戏案例】
Mar 26 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
人尽可用的Windows技巧小贴士之下篇
2007/03/22 PHP
php获取远程文件大小
2015/10/20 PHP
php 输出json及显示json中的中文汉字详解及实例
2016/11/09 PHP
实例讲解YII2中多表关联的使用方法
2017/07/21 PHP
PHP使用星号替代用户名手机和邮箱的实现代码
2018/02/07 PHP
php使用pecl方式安装扩展操作示例
2019/08/12 PHP
爆炸式的JS圆形浮动菜单特效代码
2010/03/03 Javascript
jQuery中filter()和find()的区别深入了解
2013/09/25 Javascript
JS获取计算机mac地址以及IP的实现方法
2014/01/08 Javascript
分享十五款 jQuery 社交网络分享插件
2015/05/16 Javascript
详细分析JavaScript变量类型
2015/07/08 Javascript
jquery分隔Url的param方法(推荐)
2016/05/25 Javascript
微信小程序 自己制作小组件实例详解
2016/12/22 Javascript
Require.js的基本用法详解
2017/07/03 Javascript
jQuery基于Ajax实现读取XML数据功能示例
2018/05/31 jQuery
Vue实现 点击显示再点击隐藏效果(点击页面空白区域也隐藏效果)
2020/01/16 Javascript
[52:10]LGD vs Optic Supermajor小组赛D组胜者组决赛 BO3 第二场 6.3
2018/06/04 DOTA
Python break语句详解
2014/03/11 Python
python读取TXT到数组及列表去重后按原来顺序排序的方法
2015/06/26 Python
一个月入门Python爬虫学习,轻松爬取大规模数据
2018/01/03 Python
OpenCV HSV颜色识别及HSV基本颜色分量范围
2019/03/22 Python
python3实现字符串操作的实例代码
2019/04/16 Python
python 使用plt画图,去除图片四周的白边方法
2019/07/09 Python
python中dict()的高级用法实现
2019/11/13 Python
基于Python 中函数的 收集参数 机制
2019/12/21 Python
python 如何对logging日志封装
2020/12/02 Python
台湾母婴用品购物网站:Infant婴之房
2018/06/15 全球购物
在网络中有两台主机A和B,并通过路由器和其他交换设备连接起来,已经确认物理连接正确无误,怎么来测试这两台机器是否连通?如果不通,怎么来判断故障点?怎么排
2014/01/13 面试题
大学生求职工作的自我评价
2014/02/13 职场文书
2014中考励志标语
2014/06/05 职场文书
干部作风整顿个人剖析材料
2014/10/06 职场文书
晋江市委常委班子四风问题整改工作方案
2014/10/26 职场文书
学校党支部公开承诺书
2015/04/30 职场文书
2015年全国助残日活动方案
2015/05/04 职场文书
大学生,三分钟即兴演讲稿
2019/07/22 职场文书
深入理解 Golang 的字符串
2022/05/04 Golang