php与数据库表交互,php 设计模式-数据映射模式(应用程序与数据库交互模式)...

前面提到的设计模式大大提高了代码的可读性与可维护性。然而,在WEB应用设计与开发中一个基本的需求与挑战:数据库应用,这些设计模式都没有涉及到。数据映射模式使您能更好的组织你的应用程序与数据库进行交互。

下面我将用实际代码说明,如果一个表发生变动。我们要修改客户端代码就可以了。特别是游戏项目,需求经常可能会经常变动。修改表结构,可能引起大片代码的改动。

首先我们使用pdo进行数据库访问:

/**

* Filename:db.class.php

*

* db class ,use PDO lib

*

* @author guisu.huang

* @version 1.0

*

*/

class Db {

public static $db = null;

private $_dbh = null;

public static function getInstance()

{

if( self::$db == null ){

self::$db = new self(BACKEND_DBHOST ,BACKEND_DBUSER ,BACKEND_DBPW ,BACKEND_DBNAME);

}

return self::$db;

}

private function __construct( $host ,$user ,$pass ,$dbname ){

try {

$this->_dbh = new PDO('mysql:dbname='.$dbname.';host='.$host,$user,$pass);

$this->_dbh->query('SET NAMES '. BACKEND_DBCHARSET);

$this->_dbh->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);

$this->_dbh->setAttribute(PDO::ATTR_ERRMODE, true);

} catch (PDOException $e) {

throw new Exception('Can not connect db');

}

}

private function getExecuteResult($sql, $sth){

$type = strtolower(substr(trim($sql), 0,6));

switch ($type) {

case 'update': case 'delete':

$result = $sth->rowcount();//返回影响的行数

break;

case 'insert':

$result = $this->getLastId();

break;

case 'select':

$result = $sth->fetchAll(PDO::FETCH_ASSOC);

break;

default:

break;

}

return $result;

}

/**************************************sql ************************/

public function getOne($sql){

try {

$rs = $this->_dbh->query($sql);

$result = $rs->fetch(PDO::FETCH_ASSOC);

if(!empty($result)) {

return $result;

}

} catch (PDOException $e) {

throw new Exception($this->_dbh->errorInfo());

}

return false;

}

public function getAll($sql){

try {

$rs = $this->_dbh->query($sql);

$result = $rs->fetchAll(PDO::FETCH_ASSOC);

if(!empty($result)) {

return $result;

}

} catch (PDOException $e) {

throw new Exception($this->_dbh->errorInfo());

}

return false;

}

public function exec($sql){

try {

$exec = $this->_dbh->exec($sql);

} catch (PDOException $e){

throw new Exception($this->_dbh->errorInfo());

}

return $exec;

}

/**

* 不关注键值

*  Execute a prepared statement by passing an array of values

$sth = $dbh->prepare('SELECT name, colour, calories

FROM fruit

WHERE calories 

$sth->execute(array(150, 'red'));

$red = $sth->fetchAll();

$sth->execute(array(175, 'yellow'));

$yellow = $sth->fetchAll();

* @param unknown_type $sql

* @param unknown_type $arr

* @return unknown

*/

public function executeArr($sql, $arr){

try {

$sth = $this->_dbh->prepare($sql);

$r = $sth->execute($arr);

if ($r) {

return  $this->getExecuteResult($sql, $sth);

}

} catch (PDOException $e){

throw new Exception($e->getMessage() . $this->_dbh->errorInfo());

}

}

/**

* 关联数组:

*  Execute a prepared statement by passing an array of values

$sql = 'SELECT name, colour, calories

FROM fruit

WHERE calories 

$sth = $dbh->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));

$sth->execute(array(':calories' => 150, ':colour' => 'red'));

$red = $sth->fetchAll();

*

* @param unknown_type $sql

* @param unknown_type $arr

* @return unknown

*/

public function executeAsoc($sql, $arr){

try {

$array = array();

if ($arr) {

foreach ($arr as $key=>$v) {

if (strpos($sql, ':' . $key )!==false) {

$array[':' . $key] = $v;

}

}

}

$sth = $this->_dbh->prepare($sql);

$r = $sth->execute($array);

if ($r) {

return  $this->getExecuteResult($sql, $sth);

}

} catch (PDOException $e){

throw new Exception($e->getMessage() . $this->_dbh->errorInfo());

}

}

public function beginTransaction(){

return $this->_dbh->beginTransaction();

}

public function commit(){

return $this->_dbh->commit();

}

public function rollBack(){

return $this->_dbh->rollBack();

}

public function getLastId()

{

return $this->_dbh->lastInsertId();

}

}

?>

数据映相关类射类,使用__call达到动态生成getter 和setter方法.

/**

* 抽象数据映射

*

*/

abstract  class Table{

public function __call($method, $args) {

if (preg_match('/^(get|set)(\w+)/', strtolower($method), $match)

&& $attribute = $this->validateAttribute($match[2])) {

if ('get' == $match[1]) {

return $this->$attribute;

} else {

$this->$attribute = $args[0];

}

}else {

throw new Exception(

'Call to undefined method ' . __CLASS__  . '::'.$method.'()');

}

}

protected function validateAttribute($method) {

if ( in_array(strtolower($method), array_keys(get_class_vars(get_class($this))))) {

return strtolower($method);

}

}

}

/**

* 数据映射到表

* 一般根据表的结构由工具自动生成,

* 要不然程序员经常得copy和修改这个类

*

*/

class UserTable extends Table {

/**

* fields

*

* @var unknown_type

*/

protected $uid = null;

protected $username = null ;

protected $level = null;

protected $exp = null;

protected $ctime = null;

protected $mtime = null;

/**

* table

*

* @var unknown_type

*/

public   $tableName = 'user';

public  $primaryKey = 'uid';

public  static $tablefileds = array(

'uid',

'username',

'level',

'exp',

'ctime',

'mtime',

);

/**

* 对象生成数组

*

* @return array

*/

function toArray(){

$arr = array();

foreach (UserTable::$tablefileds as $filed) {

$getMethod  = 'get' .ucwords($filed);

$value = $this->$getMethod();

if ($value !== null) {

$arr[$filed] = $value;

}

}

return $arr;

}

/**

* 数组生成对象

*

* @return array

*/

function toObj($arr){

if (!$arr) {

return $this;

}

foreach (UserTable::$tablefileds as $filed) {

$setMethod  = 'set' .ucwords($filed);

$this->$setMethod($arr[$filed]);

}

return $this;

}

}

/**

*

*

*/

class Mapper{

protected  $conn = null;

/**

* 自动插入

* 不想对某一列插入,把对应的属性设置成null就ok

*

* @param Table $table

* @return unknown

*/

function save(Table $table){

$arr  =  $table->toArray();

$set = '';

if ($arr) {

foreach ($arr as $field=> $v) {

if ($set) $set .=',';

$set .= $field . "='" . $v ."'";

}

}

if ($set) {

$this->conn->exec( 'insert into ' . $table->tableName . ' SET ' . $set);

return $this->conn->getLastId();

}

}

/**

* 更新

* 不想对某一列更新,把对应的属性设置成null就ok

*

* @param Table $table

* @return unknown

*/

function update(Table $table){

$arr  =  $table->toArray();

$set = '';

if ($arr) {

foreach ($arr as $field=> $v) {

if ($set) $set .=',';

$set .= $field . "='" . $v ."'";

}

}

$primayGet = 'get'.ucwords($table->primaryKey);

if ($set) {

return $this->conn->exec( 'update ' . $table->tableName . ' SET ' . $set . ' where ' . $table->primaryKey ."='" . $table->$primayGet() . "'" );

}

}

}

class UserMapper extends Mapper {

const INSERT_SQL = "insert into user (username, level,exp, ctime, mtime) values (:username, :level, :exp, now(), now())";

const UPDATE_SQL = "update user SET username=:username, level=:level, exp=:exp WHERE uid=:uid ";

const SELECT_SQL = "select * from user  WHERE uid=:uid ";

const DELETE_SQL = "delete from user  WHERE uid=:uid ";

function __construct(){

$this->conn =  Db::getInstance();

}

/**

* 我们可以实现覆盖save

*

* @param unknown_type $userTable

*/

public function save2($userTable) {

$rs =  Db::getInstance()->executeArr( self::INSERT_SQL, $userTable->toArray());

return $rs;

}

/**

* Enter description here...

*

* @param unknown_type $userTable

*/

public function update2($userTable) {

return $this->conn->execute(self::UPDATE_SQL, $userTable->toArray());

}

/**

* Enter description here...

*

* @param unknown_type $arr

*/

public function find($userTable) {

$rs = $this->conn->executeAsoc( self::SELECT_SQL, $userTable->toArray());

return $rs ? $userTable->toObj($rs[0]) : $userTable;

}

}

?>

实际客户测试:

/**

* 数据库配置文件

*

*/

define('BACKEND_DBHOST', 'localhost');

define('BACKEND_DBUSER', 'root');

define('BACKEND_DBPW', '123456');

define('BACKEND_DBNAME', 'sample');

define('BACKEND_DBCHARSET', 'utf-8');

//sql

/*

CREATE TABLE IF NOT EXISTS `user` (

`uid` int(11) NOT NULL AUTO_INCREMENT,

`username` varchar(64) NOT NULL,

`level` int(11) NOT NULL DEFAULT '0',

`exp` int(11) NOT NULL DEFAULT '0',

`ctime` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',

`mtime` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',

PRIMARY KEY (`uid`),

KEY `username` (`username`)

) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=12 ;

*/

class client{

static function main(){

$userMapper = new UserMapper();

$user = new UserTable();

//插入

//$user->setUserName('guisu');

//$user->setLevel(1);

//$user->setExp(10);

//

//$userMapper = new UserMapper();

//$r = $userMapper->save($user);

//查找

$user->setUid(10);

$user = $userMapper->find($user);

var_dump($user);

//更新

$user->setUserName('guisu2');

$r = $userMapper->update($user);

var_dump($r);

}

}

一般,client是业务逻辑层,UserMapper是数据访问层。UserTable底层数据结构。

我们尽量做到如果表User修改了:

1)工具重新自动生成UserTable类

2)只修改client代码和少量的UserMapper代码,一般修改UserMapper的常量const的内容就可以了。

原创文章,作者:s19930811,如若转载,请注明出处:http://www.178linux.com/2827

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值