介绍
介绍
今天我们来完成数据库操作对象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.
微信公众号的文章发出去之后是不能编辑的,但是福哥偶尔会修复一些描述不到位、示例不正确、结构不清晰等等的文章错误,这些只能在网站上才能看到最新版本内容,望大家知晓~~