基于PHP简单的ORM实现(postgresql)http://xialluyouyue.iteye.com/blog/2237114
为了减少不必要的数据库查询,对数据库的影响,代码复制,我们需要更加智能方式实现ORM,需要惰性实例化,属性监控,代码可重用性,减少对底层数据库影响以及不必要主动查询的危险。
定义一个DataboundObject类,该类是一个抽象类,不仅提供子类不需要重新生成最终方法(并且,通过final关键字表明该方法不可以重载),还声明了某些必须子类实现的方法,该类可以直接放在工具类中。
命名:DataBoundObject.php
<?php
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
abstract class DataBoundObject {
protected $ID;
protected $objPDO;
protected $strTableName;
protected $arRelationMap;
protected $blForDeletion;
protected $blIsLoaded;
protected $arModifiedRelation;
abstract protected function DefineTableName();
abstract protected function DefineRelationMap();
public function __construct(PDO $objPDO,$id = null) {
$this->strTableName = $this->DefineTableName();
$this->arRelationMap = $this->DefineRelationMap();
$this->objPDO = $objPDO;
$this->blIsLoaded = false;
if(isset($id)){
$this->ID = $id;
}
$this->arModifiedRelation = [];
}
public function load(){
if(isset($this->ID)){
$strQuery = "SELECT ";
foreach ($this->arRelationMap as $key => $value) {
$strQuery .= "\"".$key."\",";
}
$strQuery = substr($strQuery, 0, strlen($strQuery)-1);
$strQuery .=" FROM ".$this->strTableName." WHERE \"id\" = :eid";
$objStatement = $this->objPDO->prepare($strQuery);
$objStatement->bindParam(':eid', $this->ID, PDO::PARAM_INT);
$objStatement->execute();
$arRow = $objStatement->fetch(PDO::FETCH_ASSOC);
foreach ($arRow as $key => $value) {
$strMember = $this->arRelationMap[$key];
if(property_exists($this, $strMember)){
if(is_numeric($value)){
eval('$this->'.$strMember .' = '.$value.';');
}else{
eval('$this->'.$strMember.' = "'.$value.'";');
}
}
}
$this->blIsLoaded = true;
}
}
public function Save(){
if(isset($this->ID)){
$strQuery = 'UPDATE "'.$this->strTableName.'" SET ';
foreach ($this->arRelationMap as $key => $value) {
eval('$actualVal = &$this->'.$value.';');
if(array_key_exists($value, $this->arModifiedRelation)){
$strQuery .= '"' .$key. "\" = :$value,";
}
}
$strQuery = substr($strQuery, 0,strlen($strQuery)-1);
$strQuery .=' WHERE "id"=:eid';
unset($objStatement);
$objStatement = $this->objPDO->prepare($strQuery);
$objStatement->bindValue(':eid', $this->ID, PDO::PARAM_INT);
foreach ($this->arRelationMap as $key => $value) {
eval('$actualVal = &$this->'.$value.';');
if(array_key_exists($value, $this->arModifiedRelation)) {
if(is_int($actualVal)){
$objStatement->bindValue(':'.$value, $this->$value, PDO::PARAM_INT);
}elseif($actualVal == NULL){
//postgresql:if some column type is null,update will cause error,u need insert null,not ''
$objStatement->bindValue(':'.$value, NULL, PDO::PARAM_STR);
}else{
$objStatement->bindValue(':'.$value, $this->$value, PDO::PARAM_STR);
}
}
}
$objStatement->execute();
echo '更新成功';exit;
}else{
$strValueList = "";
$strQuery = 'INSERT INTO "'.$this->strTableName.'" (';
foreach ($this->arRelationMap as $key => $value) {
eval('$actualVal = &$this->'.$value.';');
if(isset($actualVal)){
if(array_key_exists($value, $this->arModifiedRelation)){
$strQuery .= '"' .$key. '",';
$strValueList .= ":$value,";
}
}
}
$strQuery = substr($strQuery, 0, strlen($strQuery)-1);
$strValueList = substr($strValueList, 0, strlen($strValueList)-1);
$strQuery .= ") VALUES (";
$strQuery .= $strValueList;
$strQuery .= ")";
unset($objStatement);
$objStatement = $this->objPDO->prepare($strQuery);
foreach ($this->arRelationMap as $key => $value) {
eval('$actualVal = &$this->'.$value.';');
if(isset($actualVal)){
if(array_key_exists($value, $this->arModifiedRelation)){
if(is_int($actualVal) || $actualVal == NULL){
$objStatement->bindValue(':'.$value, $actualVal, PDO::PARAM_INT);
}else{
$objStatement->bindValue(':'.$value, $actualVal, PDO::PARAM_STR);
}
}
}
}
$objStatement->execute();
$this->ID = $this->objPDO->lastInsertId($this->strTableName."_id_seq");
}
}
public function MarkFordeletion(){
$this->blForDeletion = true;
}
public function __destruct() {
if(isset($this->ID)){
if($this->blForDeletion == true){
$strQuery = 'DELETE FROM "'.$this->strTableName.'" WHERE "id" =:eid';
$objStatement = $this->objPDO->prepare($strQuery);
$objStatement->bindValue(':eid', $this->ID, PDO::PARAM_INT);
$objStatement->execute();
echo '删除成功';exit;
}
}
}
public function __call($strFunction, $arArguments) {
$strMethodType = substr($strFunction, 0,3);
$strMethodMember = substr($strFunction, 3);
switch ($strMethodType) {
case 'set':
return ($this->SetAccessor($strMethodMember, $arArguments[0]));
break;
case 'get':
return ($this->GetAccessor($strMethodMember));
}
return (false);
}
private function SetAccessor($strMember,$strNewValue){
if(property_exists($this, $strMember)){
if(is_numeric($strNewValue)){
eval('$this->'.$strMember.' = '.$strNewValue.';');
}else{
eval('$this->'.$strMember.' = "'.$strNewValue.'";');
}
$this->arModifiedRelation[$strMember] = "1";
}else{
return (false);
}
}
private function GetAccessor($strMember){
if($this->blIsLoaded != true){
$this->load();
}
if(property_exists($this, $strMember)){
eval('$strRetVal = $this->'.$strMember.';');
return ($strRetVal);
}else{
return (false);
}
}
}
我们还是用system_user表(postgresql)
定义User类进行继承DataBoundObject类,
命名User.php
<?php
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
require_once 'DataBoundObject.php';
class User extends DataBoundObject{
protected $FirstName;
protected $LastName;
protected $Username;
protected $Password;
protected $EmailAddress;
protected $DateLastLogin;
protected $TimeLastLogin;
protected $DateAccountCreated;
protected $TimeAccountCreated;
protected function DefineTableName() {
return ("system_user");
}
protected function DefineRelationMap() {
return ([
"id" => "ID",
"first_name" => "FirstName",
"last_name" => "LastName",
"username" => "Username",
"md5_pw" => "password",
"email_address" => "EmailAddress",
"date_last_login" => "DateLastLogin",
"time_last_login" => "TimeLastLogin",
"date_account_created" => "DateAccountCreated",
"time_account_created" => "TimeAccountCreated"
]);
}
}
下面我们进行测试:
命名为TestSystemUser.php
<?php
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
require_once 'PdoFactory.php';
require_once 'DataBoundObject.php';
require_once 'User.php';
$dsn ="pgsql:host=192.168.1.234;port=5432;dbname=dbname;";
$objPdo = PdoFactory::getPDO($dsn,'postgres','123456',[]);
$objUser = new User($objPdo);
$objUser->setFirstName('Kavin');
$objUser->setLastName('Green');
$objUser->setDateAccountCreated(date('Y-m-d'));
print "First name is ".$objUser->getFirstName()."<br />";
print "Last name is ".$objUser->getLastName()."<br />";
$objUser->Save();
$id = $objUser->getID();
print "ID in database is".$id."<br />";
unset($objUser);
$objUser = new User($objPdo,$id);
$objUser->setFirstName('Tobo11');
$objUser->setLastName('Jimlin111');
print "Saving.....";
$objUser->Save();
测试结果
First name is Kavin
Last name is Green
ID in database is18
Saving.....更新成功
上述基本是ORM实现基本原理,需要进一步进行该进,只是测试用。