介绍
介绍
今天我们来完成数据库操作对象TFDO的设计和实现,TFDO是基于PDO扩展开发的,所以我们需要在环境里面配置PDO扩展,使用TFLinux的童鞋们就省去了这个步骤,因为福哥已经带着大家配置了PDO扩展了。
有的童鞋可能会有疑问,既然PDO可以实现对数据库的操作,我们为什么不直接使用PDO对象而非要基于它封装一个TFDO对象呢?难道只是为了换个对象名称吗?当然不是为了换个名字这个目的了,这里面有个很重要的考量,如果我们直接使用PDO对象会有如下几方面的问题:
如果PDO对象升级了,更新了函数参数,甚至改变使用方法,那么会造成所有用到PDO对象的代码全部需要整理一遍,这个工作量忒大了点。
如果PDO对象哪天停止维护了,需要替换新的扩展或者新的解决方案,同样会影响所有调用PDO对象的代码,这是在太恐怖了。
PDO对象本身的函数不见得会适合我们的开发环境,为了项目开发便利,我们需要对PDO原生函数进行一些加工改造。
PDO
首先我们先来了解一下PDO对象的使用方法,我们的TFLinux里面安装的数据库是MySQL,我们用它来测试PDO对象的使用。
连接数据库
首先我们需要对PDO对象进行初始化,童鞋们看过前面的知识的都知道,我们曾经在“做个搜索引擎”的Python项目里面使用过MySQL数据库,那里面使用的账号是tfse,我们可以直接拿来测试使用。
$host = "127.0.0.1";
$user = "root";
$pwd = "abcdef";
$db = "tfse";
$charset = "utf8";
try{
// connect
$mysqlObj = new \PDO("mysql:host=" . $host,
$user,
$pwd,
array(
\PDO::ATTR_TIMEOUT => 5,
));
$mysqlObj->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
// use db
$mysqlObj->exec("use `". $db. "`");
// set charset
$mysqlObj->exec("set names `". $charset. "`");
}
catch (\PDOException $e){
var_dump($e);
}读取数据
现在我们将websites表里的“tongfu.net”查询出来。
$host = "127.0.0.1";
$user = "root";
$pwd = "abcdef";
$db = "tfse";
$charset = "utf8";
try{
// connect
$mysqlObj = new \PDO("mysql:host=" . $host,
$user,
$pwd,
array(
\PDO::ATTR_TIMEOUT => 5,
));
$mysqlObj->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
// use db
$mysqlObj->exec("use `". $db. "`");
// set charset
$mysqlObj->exec("set names `". $charset. "`");
// query
$sql = "select * from websites where domainName = :str";
$rs = $mysqlObj->prepare($sql);
$rs->bindValue(":str", "tongfu.net", PDO::PARAM_STR);
$rs->execute();
// fetch
$row = $rs->fetch(\PDO::FETCH_ASSOC);
var_dump($row);
}
catch (\PDOException $e){
var_dump($e);
}写入数据
现在我们通过PDO修改一下“tongfu.net”这行数据。
代码
$host = "127.0.0.1";
$user = "root";
$pwd = "abcdef";
$db = "tfse";
$charset = "utf8";
try{
// connect
$mysqlObj = new \PDO("mysql:host=" . $host,
$user,
$pwd,
array(
\PDO::ATTR_TIMEOUT => 5,
));
$mysqlObj->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
// use db
$mysqlObj->exec("use `". $db. "`");
// set charset
$mysqlObj->exec("set names `". $charset. "`");
// query
$sql = "select * from websites where domainName = :str";
$rs = $mysqlObj->prepare($sql);
$rs->bindValue(":str", "tongfu.net", PDO::PARAM_STR);
$rs->execute();
// fetch
$row = $rs->fetch(\PDO::FETCH_ASSOC);
var_dump($row);
// update
$sql = "update websites set title = :str1 where domainName = :str2";
$rs = $mysqlObj->prepare($sql);
$rs->bindValue(":str1", "update by PDO");
$rs->bindValue(":str2", "tongfu.net");
$rs->execute();
}
catch (\PDOException $e){
var_dump($e);
}修改前

修改后

TFDO
前面我们已经了解到了PDO原生方法的使用技巧,大家可以感觉到PDO的这些操作还是有点繁琐,针对这些我们进行一些封装。
TFDO对象我们放入了Database\SQL\TFDO路径下面,程序文件名称是TFDO.inc.php。使用TFDO需要在TFRouteMap.php里面包含进来。
构造器
public function __construct($driver, $host=null, $port=null, $user=null, $pwd=null, $db=null, $charset=null){
$this->driver = $driver;
$this->host = $host;
$this->port = $port;
$this->user = $user;
$this->pwd = $pwd;
$this->db = $db;
$this->charset = $charset;
$this->lastErrmsg = 0;
$this->lastErrcode = "";
}connect
public function connect(){
switch($this->driver){
case TFDO::T_MYSQL:
if($this->host == null){
$this->host = "localhost";
}
if($this->port == null){
$this->port = 3306;
}
if($this->user == null){
$this->user = "root";
}
if($this->pwd == null){
$this->pwd = "";
}
if($this->db == null){
$this->db = "test";
}
if($this->charset == null){
$this->charset = "utf8";
}
try{
// connect
$this->PDO = new \PDO("mysql:host=". $this->host,
$this->user,
$this->pwd,
array(
\PDO::ATTR_TIMEOUT => 15,
));
$this->PDO->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
// use db
$this->PDO->exec("use `". $this->db. "`");
// set charset
$this->PDO->exec("set names `". $this->charset. "`");
}
catch(\PDOException $e){
throw $e;
}
break;
default:
throw new \Exception("invalid type of driver of TFDO", 10001001);
}
}fetchOne
public function fetchOne(string $sql, array $params=null):?array {
try{
// query
$rs = $this->PDO->prepare($sql);
if(is_array($params)){
foreach($params as $param){
$rs->bindValue($param['key'], $param['value'], $param['type']);
}
}
$rs->execute();
// fetch
$row = $rs->fetch(\PDO::FETCH_ASSOC);
return $row;
}
catch(\PDOException $e){
$this->lastErrcode = $e->getCode();
$this->lastErrmsg = $e->getMessage();
}
return null;
}fetchAll
public function fetchAll(string $sql, array $params=null):?array {
try{
// query
$rs = $this->PDO->prepare($sql);
if(is_array($params)){
foreach($params as $param){
$rs->bindValue($param['key'], $param['value'], $param['type']);
}
}
$rs->execute();
// fetch
$rows = array();
while($row = $rs->fetch(\PDO::FETCH_ASSOC)){
$rows[] = $row;
}
return $rows;
}
catch(\PDOException $e){
$this->lastErrcode = $e->getCode();
$this->lastErrmsg = $e->getMessage();
}
return null;
}execute
public function execute(string $sql, array $params=null):bool {
try{
// execute
$rs = $this->PDO->prepare($sql);
if(is_array($params)){
foreach($params as $param){
$rs->bindValue($param['key'], $param['value'], $param['type']);
}
}
$rs->execute();
return true;
}
catch(\PDOException $e){
$this->lastErrcode = $e->getCode();
$this->lastErrmsg = $e->getMessage();
}
return false;
}讲解
TFDO
现在我们来讲解一下TFDO对象。
构造器
在构造器里面我们将用户传入的参数保存到了TFDO的内部属性里面。
connect
在这个方法里面,我们通过内部属性初始化了PDO对象。同时我们还选择了数据库,还设置默认编码。
fetchOne
在这个方法里面,我们使用PDO对象进行了数据的读取操作,这个方法仅仅会将查询到的第一行数据提取出来。
fetchAll
在这个方法里面,我们使用PDO对象进行了数据的读取操作,这个方法会将查询到全部数据都提取出来放入一个二维数组里面。
execute
在这个方法里面,我们使用PDO对象进行了数据的写入操作,并返回了处理结果。
测试
现在我们使用TFDO来实现前面用PDO实现的功能。
$host = "127.0.0.1";
$user = "root";
$pwd = "abcdef";
$db = "tfse";
$charset = "utf8";
// connect
$myTFDOObj = new TFDO(TFDO::T_MYSQL, $host, null, $user, $pwd, $db, $charset);
$myTFDOObj->connect();
// fetch one
$sql = "select * from websites where domainName = :str";
$row = $myTFDOObj->fetchOne($sql, array(
array('key'=>":str", 'value'=>"tongfu.net", 'type'=>\PDO::PARAM_STR)
));
var_dump($row);
// fetch all
$sql = "select * from websites limit 3";
$rows = $myTFDOObj->fetchAll($sql);
var_dump($rows);
// update
$sql = "update websites set title = :str1 where domainName = :str2";
$result = $myTFDOObj->execute($sql, array(
array('key'=>":str1", 'value'=>"update by PDO", 'type'=>\PDO::PARAM_STR),
array('key'=>":str2", 'value'=>"tongfu.net", 'type'=>\PDO::PARAM_STR)
));
var_dump($result);总结
今天我们实现了TFDO对象的设计,将复杂的PDO对象的操作进行了简化。最主要的是,我们可以不断地对这个TFDO对象进行优化、改进。
改进对象需要注意一些问题:
不要改动现有方法的名称和参数
不要改动现有对象的namespace路径
不要改动现有对象的名称
我们可以添加新方法,这个新方法的功能可以和现有方法类似,但是绝对不能改掉现有的方法的名称或者参数,哪怕它是多么的不合理!
我们可以建立新对象,但是绝对不能改版对象的名称,无论它是多么不好看,甚至有错别字!
5. P.S.
微信公众号的文章发出去之后是不能编辑的,但是福哥偶尔会修复一些描述不到位、示例不正确、结构不清晰等等的文章错误,这些只能在网站上才能看到最新版本内容,望大家知晓~~