1. 程式人生 > >PHP面向對象之工作單元

PHP面向對象之工作單元

pan cte dsn per array 特定 back fun sel

/*
工作單元
這個模式涉及到了領域模型、數據映射器和標識映射,這裏就統一進行整理和回顧了。
$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數據

PHP面向對象之工作單元