『PHP学习笔记』系列十二:单例模式二次封装PDO操作类

7 篇文章 0 订阅

PDO扩展:

定义:PDO扩展,即PDO提供了一套帮助用户实现多数据库操作的统一接口,通过使用PDO,开发人员不需要额外自定义数据库对应的操作类,从而简化开发过程。

1,PDO在PHP5以前,是需要手动加载扩展的,在php.ini配置文件中,会有这么一个扩展(在PHP5以后就自动加载了不需要手动再加载)。 

;extension = pdo                #现在php.ini中找不到该配置项了

2,PDO是一种支持多种数据库的扩展,那就意味着PDO很庞大,所以为了保证PHP运行的效率(系统会自动在开始时加载扩展),默认并没有开启对数据库产品的对应扩展,因此还需要在php.ini中开启目前项目所需要的PDO对应数据库产品的支持 。

;extension=pdo_firebird
extension=pdo_mysql            #绝大部分项目使用的,只要去掉注释重启Apache即可
;extension=pdo_oci
;extension=pdo_odbc
;extension=pdo_pgsql
;extension=pdo_sqlite

3,加载PDO对mysql数据库产品的扩展,重启Apache,然后通过phpinfo()函数就可以查看PDO的加载情况了,至少有两个加载才算成功:PDO本身和PDO针对的数据库产品 。

PDO常用方法: 

  • PDO::__construct():实例化PDO对象

  • PDO::exec():执行一个写操作SQL指令,返回受影响的行数

  • PDO::query():执行一个读操作SQL指令,返回一个PDOStatement类对象(后者进行数据解析操作)

  • PDO::errorCode()和PDO::errorInfo():获取上次错误的信息(错误码和错误描述数组)

PDO操作: 

PDO是别人提供的一套扩展, 使用扩展库其实最简单的一种方式就是遵循别人所提供的操作手册,操作手册里不单有各种方法的介绍,还会有很多其他使用者所提供的案例以及问题解决方案。

PDO手册查阅

 

定义:手册查阅,是指对于已经添加到PHP系统内的工具的使用查询。通过翻阅手册,可以快速的了解一些工具或者扩展的功能和使用方式。

查询方式1:进入到操作手册,然后打开目录列表:函数参考->数据库扩展->数据库抽象层->PDO

注意:该方式能够方便且有序的看到一个工具或者扩展的所用功能和使用方式(初学者建议)

查询方式2:直接在操作手册进入索引,然后在里面输入PDO

注意:该方式能够快速定位到查询的具体元素,需要大家在有一定了解的情况下才能完成(系统是按顺序匹配),在明确自己想要了解具体功能后,可以使用该方式

系统类使用方式:一般是了解对象的生成方式,以及各项功能的调用方式和具体效果。

系统类使用方式:除开知道怎么用之外,一定还要去了解返回结果和意外状况。

当我们了解了一个工具的基本功能后,就可以找到入口开始对其学习和使用了。例如PDO中有三个类,每个类负责不同的功能需求。我们只要掌握彼此间的功能和练习,就可以使用PDO来实现数据库操作。

 

  1. 任何一种系统支持,包括工具和扩展,都可以通过操作手册来学习和应用

  2. PDO属于一种数据库扩展,可以在函数参考下对应的数据库扩展下找到

  3. 扩展学习应该是目的性的,了解有哪些功能以及如何使用某个功能

  4. PDO有三个类需要学习

 PDO的二次封装:


 封装PDO,即对PDO进行二次封装,从而让原本多处需要使用PDO的地方,能够直接使用二次封装的类,简化数据库操作。该封装并非完整封装,属于实用二次封装。

 代码实现:(这里我们使用单例模式进行封装以保持对象的完整性)

<?php
/**
 * 使用命名空间方便使用
 * PDO的实例化:得到PDO对象,而且PDO对象需要在不同的方法中使用,可以考虑将PDO得到的对象保存在属性中
 * 写操作:包含普通SQL执行返回受影响行和获取自增长ID
 * 查操作:包含单行查询和多行查询
 * 隐藏操作:异常处理的封装
 * 其他操作:根据实际需求增加对应功能即可
 * 设计模式:单例模式,不允许在同一脚本中多次实例化
 */
// 命名空间:因为PDO通常属于核心类(项目中几乎每次都会访问数据库),使用核心关键字core命名
namespace core;

//有了命名空间,所以PDO的三个类就不再直接用,需要使用完全限定名称访问,为了方便,可以事先引入元素
use \PDO;
use \PDOException;

class MyPDO {
	//定义属性
	private $pdo;
	private $fetch_mode;
	// private static $instance = null;
	/**
	 * 构造方法完成初始化
	 * 默认采用PDO异常和获取关联数组设定
	 */
	private function __construct($dbinfo = array(), $drivers = array()) {
		//若要考虑细致,可以看看是否存在
		$type = $dbinfo['type'] ?? 'mysql'; //默认为mysql数据库
		$host = $dbinfo['host'] ?? 'localhost';
		$port = $dbinfo['port'] ?? '3306';
		$username = $dbinfo['username'] ?? 'root';
		$password = $dbinfo['password'] ?? 'root';
		$dbname = $dbinfo['dbname'] ?? 'fate';
		$charset = $dbinfo['charset'] ?? 'utf8';
		//fetchmode不能在初始化的时候实现,需要在得到PDOStatement类对象后设置
		$this->fetch_mode = $drivers[PDO::ATTR_DEFAULT_FETCH_MODE] ?? PDO::FETCH_ASSOC;
		//控制属性
		if (!isset($drivers[PDO::ATTR_ERRMODE])) {
			$drivers[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION;
		}
		//连接认证
		try {
			//增加错误抑制符防止意外
			$this->pdo = @new PDO($type . ':host=' . $host . ';port=' . $port . ';dbname=' . $dbname, $username, $password, $drivers);
		} catch (PDOException $e) {
			// echo '连接错误!<br/>';
			// echo '错误文件为:' . $e->getFile() . '<br/>';
			// echo '错误行号为:' . $e->getLine() . '<br/>';
			// echo '错误描述为:' . $e->getMessage() . '<br/>';
			// die();
			$this->myException($e);
		}
		//设定字符集
		try {
			$this->pdo->exec("set names " . $charset);
		} catch (PDOException $e) {
			$this->myException($e);
		}
	}
	//单例模式
	private static $obj = null;
	public static function getPDO($dbinfo = array(), $drivers = array()) {
		//判断是否需要重新产生新对象
		if (!self::$obj instanceof self) {
			self::$obj = new self($dbinfo, $drivers);
		}
		//返回对象
		return self::$obj;
	}
	//私有化克隆方法
	private function __clone() {}
	//异常处理->输出错误信息
	private function myException($e) {
		echo '连接错误!<br/>';
		echo '错误文件为:' . $e->getFile() . '<br/>';
		echo '错误行号为:' . $e->getLine() . '<br/>';
		echo '错误描述为:' . $e->getMessage() . '<br/>';
		die();
	}
	//写操作
	public function myExec($sql) {
		try {
			//调用执行:成功返回,错误捕捉
			return $this->pdo->exec($sql);
		} catch (PDOException $e) {
			$this->myException($e);
		}
	}
	//获取自增长id
	public function myLastInsertId() {
		return $this->pdo->lastInsertId();
	}
	//写方法:按条件进行但行查询或者多行查询
	public function myQuery($sql, $only = true) {
		try {
			$stmt = $this->pdo->query($sql);
			//设置查询模式
			$stmt->setFetchMode($this->fetch_mode);
			//数据解析
			if ($only) {
				return $stmt->fetch();
			} else {
				return $stmt->fetchAll();
			}
		} catch (PDOException $e) {
			$this->myException($e);
		}
	}
	/**
	 * 输出查询到的全部数据->foreach遍历输出
	 * @param array $arr,查询全部数据返回的二维数组->自定义
	 * @return echo输出遍历后的数组各项->表格的形式
	 */
	public static function getForeach($arr) {
		//表格样式
		echo "<table border='2' bordercolor='#66ccff' align='center'>";
		foreach ($arr as $key => $value) {
			// echo $value['name'] . ' ';
			// echo $value['rank'] . '<br/>';
			echo "<tr>";
			echo "<td>id:" . $value["Id"] . "</td>
            	  <td>职阶:" . $value["Rank"] . "</td>
            	  <td>真名:" . $value["Name"] . "</td>
            	  <td>最大ATK:" . $value["ATK"] . "</td>
            	  <td>最大HP:" . $value["HP"] . "</td>";
			echo "</tr>";
		}
		echo "</table>";
	}
}
//测试代码
$m = MyPDO::getPDO();
//写入数据
$sql = "INSERT INTO servant (Rank,Name,ATK,HP)
VALUES('caster','梅林',11899,14350)";
$stmt = $m->myExec($sql);
var_dump($stmt);
echo $m->myLastInsertId();
//读取数据
$sql1 = "select * from servant";
$arr = $m->myQuery($sql1, false);
$m->getForeach($arr);

运行结果: 

总结:

1,PDO的使用是经常性的,所以我们需要将PDO变得更加灵活,更加贴近我们的项目,从而实现更多代码的复用,因此需要对PDO进行二次封装;

2,PDO的封装是要根据项目需求来实现的,如果只是基础功能,那么实现了增删改查即可;而如果项目里要用到更多的内容,如事务、预处理之类的,那么就需要进行更多的封装。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值