0

0

PHP面向对象中的工作单元

炎欲天舞

炎欲天舞

发布时间:2017-08-04 17:03:52

|

1597人浏览过

|

来源于php中文网

原创


/*
工作单元
这个模式涉及到了领域模型、数据映射器和标识映射,这里就统一进行整理和回顾了。
$venue = new \woo\domain\Venue(null,"The Green Tree");
\woo\domain\ObjectWatcher::instance()->performOperations();
现在以上面的二行客户端代码为切入点大概的叙述一下这个模式是怎么工作的。
第一句在使用领域模型对象创建一个对象的时候,它就调用了标识映射ObjectWatcher类
将自己标记为一个需要新增的对象。第二句的performOperations方法将保存在标识映射器的属性$new中的对象
插入到了数据库中。注意它内部调用的$obj->finder()方法是领域模式中通过HelperFactory工厂类生成一个相对应的数据映射器类并return过来。
HelperFactory这个类下面没有具体实现(原文也没有实现),其实就是根据参数传入的类的类型使用条件分支创建对应的数据映射器。
下面直接看代码和注释进行理解。
*/



namespace woo\domain;

//标识映射
class ObjectWatcher{
    
    private $all = array();                //存放对象的小仓库
    private $dirty = array();            //存放需要在数据库中修改的对象
    private $new = array();                //存放需要在数据库中新增的对象
    private $delete = array();            //存放需要在数据库中删除的对象
    private static $instance;            //单例
    
    
    private function __construct (){}
    
    static function instance(){
        if(!self::$instance){
            self::$instance = new ObjectWatcher();
        }
        return self::$instance;
    }
    
    //获取一个唯一的标识,这里采用了领域类类名+ID的方式创建一个唯一标识,避免多个数据库表调用这个类时出现ID重复的问题
    function globalKey(DomainObject $obj){
        $key = get_class($obj) . "." . $obj->getId();
        return $key;
    }
    
    //添加对象
    static function add(DomainObject $obj){
        $inst = self::instance();
        $inst->all[$inst->globalKey($obj)] = $obj;
    }
    
    //获取对象
    static function exists($classname,$id){
        $inst = self::instance();
        $key = "$classname.$id";
        if(isset($inst->all[$key]){
            return $inst->all[$key];
        }
        return null;
    }
    
    //标记为需要删除的对象
    static function addDelete(DomainObject $obj){
        $self = self::instance();
        $self->delete[$self->globalKey($obj)] = $obj;
    }
    
    //标记为需要修改的对象
    static function addDirty(DomainObject $obj){
        $inst = self::instance();
        if(!in_array($obj,$inst->new,true)){
            $inst->dirty[$inst->globalKey($obj)] = $obj;
        }
    }
    
    //标记为需要新增的对象
    static function addNew(DomainObject $obj){
        $inst = self::instance();
        $inst->new[] = $obj;
    }
    
    //标记为干净的对象
    static function addClean(DomainObject $obj){
        $self = self::instance();
        unset($self->delete[$self->globalKey($obj)]);
        unset($self->dirty[$self->globalKey($obj)]);
        $self->new = array_filter($self->new,function($a) use($obj) {return !($a === $obj);});
    }
        
    //将上述需要增删改的对象与数据库交互进行处理    
    function performOperations(){
        foreach($this->dirty as $key=>$obj){
            $obj->finder()->update($obj);        //$obj->finder()获取一个数据映射器
        }
        foreach($this->new as $key=>$obj){
            $obj->finder()->insert($obj);
        }
        $this->dirty = array();
        $this->new = array();
    }
}


//领域模型
abstract class DomainObject{            //抽象基类
    
    private $id = -1;
    
    function __construct ($id=null){
        if(is_null($id)){
            $this->markNew();            //初始化时即被标记为需要新增的对象了
        } else {
            $this->id = $id;
        }    
    }
    
    //调用了标识映射的标记对象的方法
    function markNew(){
        ObjectWatcher::addNew($this);
    }
    
    function markDeleted(){
        ObjectWatcher::addDelete($this);
    }
    
    function markDirty(){
        ObjectWatcher::addDirty($this);
    }
    
    function markClean(){
        ObjectWatcher::addClean($this);
    }
    
    function setId($id){
        $this->id = $id;
    }
    
    function getId(){
        return $this->id;
    }
    
    
    function finder(){
        return self::getFinder(get_class($this));
    }
    
    //通过工厂类来实例化一个特定类型的数据映射器对象,例如VenueMapper
    //这个对象将被标识映射器中的performOperations方法调用用于与数据库交互进行增删改的操作
    static function getFinder($type){
        return HelperFactory::getFinder($type);
    }
    
}


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;
        $this->markDirty();                        //标记为需要修改的对象
    }
    
    function addSpace(Space $space){
        $this->spaces->add($space);
        $space->setVenue($this);
        $this->markDirty();                        //标记为需要修改的对象
    }
    
    function setName($name_s){
        $this->name = $name_s;
        $this->markDirty();                        //标记为需要修改的对象
    }
    
    function getName(){
        return $this->name;
    }
}


//领域模型
class Space extends DomainObject{
    //.........
    function setName($name_s){
        $this->name = $name_s;
        $this->markDirty();
    }
    
    function setVenue(Venue $venue){
        $this->venue = $venue;
        $this->markDirty();
    }
}


//数据映射器
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);
        }
    }
    
    //获取标记的对象
    private function getFroMap($id){
        return \woo\domain\ObjectWatcher::exists($this->targetClass(),$id);
    }
    
    
    //新增标记的对象
    private function addToMap(\woo\domain\DomainObject $obj){//////
        return \woo\domain\ObjectWatcher::add($obj);
    }
    
    
    //将数据库数据映射为对象
    function createObject($array){
        $old = $this->getFromMap($array['id']);
        if($old){return $old;}
        $obj = $this->doCreateObject($array);
        $this->addToMap($obj);
        $obj->markClean();
        return $obj;
    }

    
    function find($id){                                //通过ID从数据库中获取一条数据并创建为对象    
        $old = $this->getFromMap($id);                
        if($old){return $old}                        
        
        $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);
        $this->addToMap($object);                    
        return $object;    
    }
    
    
    function insert(\woo\domain\DomainObject $obj){            //将对象数据插入数据库
        $this->doInsert($obj);
        $this->addToMap($obj);                        
    }
    
    //需要在子类中实现的各个抽象方法
    abstract function targetClass();                                        //获取类的类型
    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);    //插入操作
    
}

class VenueMapper extends Mapper {
    function __construct (){        
        parent::__construct();    
        //预处理对象
        $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(){                    //返回一个预处理对象
        return $this->selectStmt;
    }
    
}


//客户端
$venue = new \woo\domain\Venue(null,"The Green Tree");                //在初始化时就被标记为新增对象了
$venue->addSpace(new \woo\domain\Space(null,"The Space Upstairs"));    //这二行addSpace方法因为venue已经被标记新增所以不会再标记为修改对象,但是space在初始化的时候会被标记为新增对象
$venue->addSpace(new \woo\domain\Space(null,"The Bar Stage"));      
\woo\domain\ObjectWatcher::instance()->performOperations();            //与数据库交互新增一条Venue数据,以及二条space数据

 

好买卖商城
好买卖商城

好买卖商城开源商城 是基于Opencart网店系统,针对中文用户而改进的本地化分支,是真正的开源PHP中文网店系统,兼容Opencart的插件。该系统具有易于操作的可视化安装界面、完善的前台商品展示和户在线购物车功能、强大的后台管理和维护功能模块简单易用,灵活的插件机制,更易于扩展。另外,好买卖商城开源商城 还集成集成了支付宝等支付和物流插件,更适合中文用户使用。 好买卖商城2.0开源商城流程进行

下载

相关文章

PHP速学教程(入门到精通)
PHP速学教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

php

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

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

豆包大模型
豆包大模型

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

通义千问
通义千问

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

腾讯元宝
腾讯元宝

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

文心一言
文心一言

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

讯飞写作
讯飞写作

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

即梦AI
即梦AI

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

ChatGPT
ChatGPT

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

相关专题

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

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

178

2026.01.28

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

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

35

2026.01.28

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

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

79

2026.01.28

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

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

2

2026.01.28

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

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

4

2026.01.28

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

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

8

2026.01.28

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

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

24

2026.01.27

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

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

122

2026.01.26

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

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

72

2026.01.26

热门下载

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

精品课程

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

共137课时 | 10万人学习

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号