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 相关文章推荐
php 学习资料零碎东西
Dec 04 PHP
通过PHP修改Linux或Unix口令的方法分享
Jan 30 PHP
php绘图中显示不出图片的原因及解决
Mar 05 PHP
php批量删除数据库下指定前缀的表以prefix_为例
Aug 24 PHP
PHP动态编译出现Cannot find autoconf的解决方法
Nov 05 PHP
PHP使用CURL实现多线程抓取网页
Apr 30 PHP
Yii开启片段缓存的方法
Mar 28 PHP
PHP中set_include_path()函数相关用法分析
Jul 18 PHP
php 如何设置一个严格控制过期时间的session
May 05 PHP
PHP异常处理定义与使用方法分析
Jul 25 PHP
php微信开发之关键词回复功能
Jun 13 PHP
PHP whois查询类定义与用法示例
Apr 03 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 gzip压缩输出的实现方法
2013/04/27 PHP
解析在PHP中使用mysqli扩展库对mysql的操作
2013/07/03 PHP
php数组使用规则分析
2015/02/27 PHP
PHP微信红包生成代码分享
2016/10/06 PHP
Aster vs Newbee BO5 第一场2.19
2021/03/10 DOTA
jquery 笔记 事件
2011/11/02 Javascript
JavaScript高级程序设计 读书笔记之八 Function类及闭包
2012/02/27 Javascript
jquery实现div拖拽宽度示例代码
2013/07/31 Javascript
基于jquery实现的文字向上跑动类似跑马灯的效果
2014/06/17 Javascript
深入理解javascript变量声明
2014/11/20 Javascript
Javascript中的Callback方法浅析
2015/03/15 Javascript
jQuery实现的网格线绘制方法
2016/06/20 Javascript
JS打印组合功能
2016/08/04 Javascript
jQuery移除或禁用html元素点击事件常用方法小结
2017/02/10 Javascript
js模拟微博发布消息
2017/02/23 Javascript
ReactJs实现树形结构的数据显示的组件的示例
2017/08/18 Javascript
详解基于 axios 的 Vue 项目 http 请求优化
2017/09/04 Javascript
Angular4的输入属性与输出属性实例详解
2017/11/29 Javascript
在Vue中使用echarts的方法
2018/02/05 Javascript
vue如何判断dom的class
2018/04/26 Javascript
详解vue-cli项目中怎么使用mock数据
2018/05/29 Javascript
vue超时计算的组件实例代码
2018/07/09 Javascript
移动端图片上传旋转、压缩问题的方法
2018/10/16 Javascript
JavaScript实现密码强度实时验证
2020/03/18 Javascript
如何在面试中手写出javascript节流和防抖函数
2020/10/22 Javascript
JS实现炫酷轮播图
2020/11/15 Javascript
[01:00:14]DOTA2官方TI8总决赛纪录片 真视界True Sight
2019/01/16 DOTA
Python实现多态、协议和鸭子类型的代码详解
2019/05/05 Python
python中adb有什么功能
2020/06/07 Python
python3跳出一个循环的实例操作
2020/08/18 Python
python 爬取腾讯视频评论的实现步骤
2021/02/18 Python
CSS3中box-shadow的用法介绍
2015/07/15 HTML / CSS
英国家用电器购物网站:Hughes
2018/02/23 全球购物
Linux文件系统类型
2012/09/16 面试题
音乐之声音乐广播稿
2014/09/10 职场文书
重阳节标语大全
2014/10/07 职场文书