欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  后端开发

超轻的 PHP 数据库工具包

程序员文章站 2022-03-18 11:12:18
...
一个很轻的 PHP 数据库工具包,诞生时间两天(足以证明很轻了 超轻的 PHP 数据库工具包)。
两个类,一个 Connection 管理 PDO 连接(支持多数据库),一个 QuickQuery 用来快速执行数据库操作(不用在 PDO 和 PDOStatement 之间来回折腾)
不用下载,在线就能看完。
  1. use Persistence\DbAccess;
  2. // 在框架初始化的地方添加连接信息
  3. DbAccess\Connection::add(
  4. 'default',
  5. 'sqlite',
  6. '/db/mydb.sqlite',
  7. null, null, false
  8. );
  9. // 下面是使用
  10. $conn = DbAccess\Connection::instance('default');
  11. // 查询
  12. $query = new DbAccess\QuickQuery($conn);
  13. $query->prepare('select :name as name')->execute(array(':name'=>'tonyseek'));
  14. // 对象直接作为迭代器产生数据数组
  15. foreach($query as $i) {
  16. var_dump($i);
  17. }
  18. // 如果有偏执的话,输出响应之前手动断开连接
  19. DbAccess\Connection::disconnectAll();
复制代码
  1. namespace Persistence\DbAccess;
  2. use PDO, ArrayObject, DateTime;
  3. use LogicException, InvalidArgumentException;
  4. /**
  5. * 快捷查询通道
  6. *
  7. * @version 0.3
  8. * @author tonyseek
  9. * @link http://stu.szu.edu.cn
  10. * @license http://www.opensource.org/licenses/mit-license.html
  11. * @copyright StuCampus Development Team, Shenzhen University
  12. *
  13. */
  14. class QuickQuery implements \IteratorAggregate
  15. {
  16. /**
  17. * 数据库连接
  18. *
  19. * @var \Persistence\DbAccess\Connection
  20. */
  21. private $connection = null;
  22. /**
  23. * PDO Statement
  24. *
  25. * @var PDOStatement
  26. */
  27. private $stmt = null;
  28. /**
  29. * 被检查参数集
  30. *
  31. * @var array
  32. */
  33. private $checkedParams = array();
  34. /**
  35. * 构造查询通道
  36. *
  37. * @param \Persistence\DbAccess\Connection $connection 数据库连接
  38. */
  39. public function __construct(Connection $connection)
  40. {
  41. $this->connection = $connection;
  42. }
  43. /**
  44. * 预编译 SQL 语句
  45. *
  46. * @param string $sqlCommand SQL语句
  47. * @return \Persistence\DbAccess\QuickQuery
  48. */
  49. public function prepare($sqlCommand)
  50. {
  51. // 从连接获取 PDO, 并对 SQL 语句执行 prepare, 产生 PDO Statement
  52. $this->stmt = $this->connection->getPDO()->prepare($sqlCommand);
  53. // 修改 PDO Statement 模式为关联数组数据
  54. $this->stmt->setFetchMode(PDO::FETCH_ASSOC);
  55. // 返回方法链
  56. return $this;
  57. }
  58. /**
  59. * 执行数据查询
  60. *
  61. * @throws PDOException
  62. * @return \Persistence\DbAccess\QuickQuery
  63. */
  64. public function execute($params = array())
  65. {
  66. $stmt = $this->getStatement();
  67. // 参数检查
  68. $diff = array_diff($this->checkedParams, array_keys($params));
  69. if (count($this->checkedParams) && count($diff)) {
  70. throw new InvalidArgumentException('缺少必备参数:'.implode(' | ', $diff));
  71. }
  72. // 将 PHP 数据类型对应到数据库数据类型
  73. foreach($params as $key => $value) {
  74. $type = null;
  75. switch(true) {
  76. case is_int($value):
  77. $type = PDO::PARAM_INT;
  78. break;
  79. case is_bool($value):
  80. $type = PDO::PARAM_BOOL;
  81. break;
  82. case ($value instanceof DateTime):
  83. $type = PDO::PARAM_STR;
  84. $value = $value->format(\DateTime::W3C);
  85. break;
  86. case is_null($value):
  87. $type = PDO::PARAM_NULL;
  88. break;
  89. default:
  90. $type = PDO::PARAM_STR;
  91. }
  92. $stmt->bindValue($key, $value, $type);
  93. }
  94. $stmt->execute();
  95. $this->checkedParams = array(); // 清空参数检查
  96. return $this;
  97. }
  98. /**
  99. * 获取 Statement 对象
  100. *
  101. * 返回对象可以被绑定参数重新执行, 也可以被当作迭代器遍历获取数据。
  102. *
  103. * @return \PDOStatement
  104. */
  105. public function getStatement()
  106. {
  107. if (!$this->stmt) {
  108. throw new LogicException('SQL语句应该先被 QuickQuery.prepare 预处理');
  109. }
  110. return $this->stmt;
  111. }
  112. /**
  113. * getStatement 方法的替代名
  114. *
  115. * 实现 PHP 标准库 中的 IteratorAggregate 接口, 外部可以直接将本对象作为迭代器遍
  116. * 历。和 getStatment 唯一不同之处, 是本方法不会抛出 LogicException 异常。如果
  117. * 没有事先使用 prepare 和 execute, 会返回一个空迭代器。
  118. *
  119. * @return Traversable
  120. */
  121. public function getIterator()
  122. {
  123. try {
  124. return $this->getStatement();
  125. } catch (LogicException $ex) {
  126. return new \ArrayObject();
  127. }
  128. }
  129. /**
  130. * 设置查询参数检查
  131. *
  132. * 通过此处导入的被检查查询参数, 如果没有得到赋值, 则查询时会抛出 LogicException 异常。
  133. *
  134. * @param array $params
  135. * @return \Persistence\DbAccess\QuickQuery
  136. */
  137. public function setParamsCheck(array $params)
  138. {
  139. $this->checkedParams = $params;
  140. return $this;
  141. }
  142. /**
  143. * 将结果集转换为数组
  144. *
  145. * @return array
  146. */
  147. public function toArray()
  148. {
  149. return iterator_to_array($this->getStatement());
  150. }
  151. /**
  152. * 获取最后一个插入结果(或序列)的 ID
  153. *
  154. * @param string $name
  155. * @return int
  156. */
  157. public function getLastInsertId($name=null)
  158. {
  159. return $this->connection->getPDO()->lastInsertId($name);
  160. }
  161. }
复制代码
  1. namespace Persistence\DbAccess;
  2. use InvalidArgumentException, BadMethodCallException;
  3. use PDO, PDOException;
  4. /**
  5. * 连接工厂,提供全局的PDO对象,并管理事务。
  6. *
  7. * @version 0.3
  8. * @author tonyseek
  9. * @link http://stu.szu.edu.cn
  10. * @license http://www.opensource.org/licenses/mit-license.html
  11. * @copyright StuCampus Development Team, Shenzhen University
  12. *
  13. */
  14. final class Connection
  15. {
  16. /**
  17. * Connector 实例集合
  18. *
  19. * @var array
  20. */
  21. static private $instances = array();
  22. /**
  23. * 数据库驱动名
  24. *
  25. * @var string
  26. */
  27. private $driver = '';
  28. /**
  29. * 数据库连接字符串(Database Source Name)
  30. *
  31. * @var string
  32. */
  33. private $dsn = '';
  34. /**
  35. * PDO 实例
  36. *
  37. * @var \PDO
  38. */
  39. private $pdo = null;
  40. /**
  41. * 用户名
  42. *
  43. * @var string
  44. */
  45. private $username = '';
  46. /**
  47. * 密码
  48. *
  49. * @var string
  50. */
  51. private $password = '';
  52. /**
  53. * 是否开启持久连接
  54. *
  55. * @var bool
  56. */
  57. private $isPersisten = false;
  58. /**
  59. * 是否开启仿真预编译
  60. *
  61. * @var bool
  62. */
  63. private $isEmulate = false;
  64. /**
  65. * 是否在事务中
  66. *
  67. * @var bool
  68. */
  69. private $isInTransation = false;
  70. /**
  71. * 私有构造函数,阻止外部使用 new 操作符实例化
  72. */
  73. private function __construct(){}
  74. /**
  75. * 生产 Connector 实例(多例)
  76. *
  77. * @param string $name
  78. * @return \StuCampus\DataModel\Connector
  79. */
  80. static public function getInstance($name = 'default')
  81. {
  82. if (!isset(self::$instances[$name])) {
  83. // 如果访问的实例不存在则抛出错误异常
  84. throw new InvalidArgumentException("[{$name}] 不存在");
  85. }
  86. return self::$instances[$name];
  87. }
  88. /**
  89. * 断开所有数据库实例的连接
  90. */
  91. static public function disconnectAll()
  92. {
  93. foreach (self::$instances as $instance) {
  94. $instance->disconnect();
  95. }
  96. }
  97. /**
  98. * 添加数据库
  99. *
  100. * 向实例群添加 Connector
  101. *
  102. * @param string $name 标识名
  103. * @param string $driver 驱动名
  104. * @param string $dsn 连接字符串
  105. * @param string $usr 数据库用户名
  106. * @param string $pwd 数据库密码
  107. * @param bool $emulate 仿真预编译查询
  108. * @param bool $persisten 是否持久连接
  109. */
  110. static public function registry($name, $driver, $dsn, $usr, $pwd, $emulate = false, $persisten = false)
  111. {
  112. if (isset(self::$instances[$name])) {
  113. // 如果添加的实例名已经存在则抛出异常
  114. throw new BadMethodCallException("[{$name}] 已被注册");
  115. }
  116. // 实例化自身,并推入数组中
  117. self::$instances[$name] = new self();
  118. self::$instances[$name]->dsn = $driver . ':' . $dsn;
  119. self::$instances[$name]->username = $usr;
  120. self::$instances[$name]->password = $pwd;
  121. self::$instances[$name]->driver = $driver;
  122. self::$instances[$name]->isPersisten = (bool)$persisten;
  123. self::$instances[$name]->isEmulate = (bool)$emulate;
  124. }
  125. /**
  126. * 获取 PHP Database Object
  127. *
  128. * @return \PDO
  129. */
  130. public function getPDO()
  131. {
  132. if (!$this->pdo) {
  133. // 检查 PDO 是否已经实例化,否则先实例化 PDO
  134. $this->pdo = new PDO($this->dsn, $this->username, $this->password);
  135. // 错误模式为抛出 PDOException 异常
  136. $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  137. // 开启查询缓存
  138. $this->pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, $this->isEmulate);
  139. // 开启持久连接
  140. $this->pdo->setAttribute(PDO::ATTR_PERSISTENT, $this->isPersisten);
  141. }
  142. return $this->pdo;
  143. }
  144. /**
  145. * 获取数据库驱动名
  146. *
  147. * @return string
  148. */
  149. public function getDriverName()
  150. {
  151. return $this->driver;
  152. }
  153. /**
  154. * 开始事务
  155. */
  156. public function transationBegin()
  157. {
  158. $this->isInTransation = $this->getPDO()->beginTransaction();
  159. }
  160. /**
  161. * 提交事务
  162. */
  163. public function transationCommit()
  164. {
  165. if ($this->isInTransation) {
  166. $this->getPDO()->commit();
  167. } else {
  168. trigger_error('transationBegin 应该先于 transationCommit 调用');
  169. }
  170. }
  171. /**
  172. * 回滚事务
  173. * @return bool
  174. */
  175. public function transationRollback()
  176. {
  177. if ($this->isInTransation) {
  178. $this->getPDO()->rollBack();
  179. } else {
  180. trigger_error('transationBegin 应该先于 transationRollback 调用');
  181. }
  182. }
  183. /**
  184. * 连接是否在事务中
  185. *
  186. * @return bool
  187. */
  188. public function isInTransation()
  189. {
  190. return $this->isInTransation;
  191. }
  192. /**
  193. * 在事务中执行回调函数
  194. *
  195. * @param function $callback 匿名函数或闭包函数
  196. * @param bool $autoRollback 异常发生时是否自动回滚
  197. * @throws \PDOException
  198. * @return bool
  199. */
  200. public function transationExecute($callback, $autoRollback = true)
  201. {
  202. try {
  203. // 开始事务
  204. $this->transationBegin();
  205. // 调用回调函数
  206. if (is_callable($callback)) {
  207. $callback();
  208. } else {
  209. throw new InvalidArgumentException('$callback应该为回调函数');
  210. }
  211. // 提交事务
  212. return $this->transationCommit();
  213. } catch(PDOException $pex) {
  214. // 如果开启了自动回滚, 则捕捉到 PDO 异常时先回滚再抛出
  215. if ($autoRollback) {
  216. $this->transationRollback();
  217. }
  218. throw $pex;
  219. }
  220. }
  221. /**
  222. * 安全地断开数据库连接
  223. */
  224. public function disconnect()
  225. {
  226. if ($this->pdo) {
  227. // 检查 PDO 是否已经实例化,是则设置为null
  228. $this->pdo = null;
  229. }
  230. }
  231. /**
  232. * 阻止克隆
  233. */
  234. public function __clone()
  235. {
  236. trigger_error('被阻止的 __clone 方法, Connector 是单例类');
  237. }
  238. }
复制代码