超轻的 PHP 数据库工具包

原创
2016-07-25 09:09:49 1360浏览
一个很轻的 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. }
复制代码


声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn核实处理。
上一条:php 扩展sqlsrv调用mssql存储过程 下一条:设置Mysql执行超时时间

相关文章

查看更多