0

0

总结领域模型+数据映射器的实例

零下一度

零下一度

发布时间:2017-06-23 14:35:58

|

989人浏览过

|

来源于php中文网

原创

/*这里要说明一下 因为本人比较懒 博客中相关文章的内容更多的是对<深入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);//结束

 

奇布塔
奇布塔

基于AI生成技术的一站式有声绘本创作平台

下载

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
俄罗斯Yandex引擎入口
俄罗斯Yandex引擎入口

2026年俄罗斯Yandex搜索引擎最新入口汇总,涵盖免登录、多语言支持、无广告视频播放及本地化服务等核心功能。阅读专题下面的文章了解更多详细内容。

75

2026.01.28

包子漫画在线官方入口大全
包子漫画在线官方入口大全

本合集汇总了包子漫画2026最新官方在线观看入口,涵盖备用域名、正版无广告链接及多端适配地址,助你畅享12700+高清漫画资源。阅读专题下面的文章了解更多详细内容。

17

2026.01.28

ao3中文版官网地址大全
ao3中文版官网地址大全

AO3最新中文版官网入口合集,汇总2026年主站及国内优化镜像链接,支持简体中文界面、无广告阅读与多设备同步。阅读专题下面的文章了解更多详细内容。

38

2026.01.28

php怎么写接口教程
php怎么写接口教程

本合集涵盖PHP接口开发基础、RESTful API设计、数据交互与安全处理等实用教程,助你快速掌握PHP接口编写技巧。阅读专题下面的文章了解更多详细内容。

1

2026.01.28

php中文乱码如何解决
php中文乱码如何解决

本文整理了php中文乱码如何解决及解决方法,阅读节专题下面的文章了解更多详细内容。

3

2026.01.28

Java 消息队列与异步架构实战
Java 消息队列与异步架构实战

本专题系统讲解 Java 在消息队列与异步系统架构中的核心应用,涵盖消息队列基本原理、Kafka 与 RabbitMQ 的使用场景对比、生产者与消费者模型、消息可靠性与顺序性保障、重复消费与幂等处理,以及在高并发系统中的异步解耦设计。通过实战案例,帮助学习者掌握 使用 Java 构建高吞吐、高可靠异步消息系统的完整思路。

8

2026.01.28

Python 自然语言处理(NLP)基础与实战
Python 自然语言处理(NLP)基础与实战

本专题系统讲解 Python 在自然语言处理(NLP)领域的基础方法与实战应用,涵盖文本预处理(分词、去停用词)、词性标注、命名实体识别、关键词提取、情感分析,以及常用 NLP 库(NLTK、spaCy)的核心用法。通过真实文本案例,帮助学习者掌握 使用 Python 进行文本分析与语言数据处理的完整流程,适用于内容分析、舆情监测与智能文本应用场景。

23

2026.01.27

拼多多赚钱的5种方法 拼多多赚钱的5种方法
拼多多赚钱的5种方法 拼多多赚钱的5种方法

在拼多多上赚钱主要可以通过无货源模式一件代发、精细化运营特色店铺、参与官方高流量活动、利用拼团机制社交裂变,以及成为多多进宝推广员这5种方法实现。核心策略在于通过低成本、高效率的供应链管理与营销,利用平台社交电商红利实现盈利。

122

2026.01.26

edge浏览器怎样设置主页 edge浏览器自定义设置教程
edge浏览器怎样设置主页 edge浏览器自定义设置教程

在Edge浏览器中设置主页,请依次点击右上角“...”图标 > 设置 > 开始、主页和新建标签页。在“Microsoft Edge 启动时”选择“打开以下页面”,点击“添加新页面”并输入网址。若要使用主页按钮,需在“外观”设置中开启“显示主页按钮”并设定网址。

52

2026.01.26

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PHP课程
PHP课程

共137课时 | 9.9万人学习

JavaScript ES5基础线上课程教学
JavaScript ES5基础线上课程教学

共6课时 | 11.2万人学习

PHP新手语法线上课程教学
PHP新手语法线上课程教学

共13课时 | 0.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号