一个很轻的 PHP 数据库工具包,诞生时间两天(足以证明很轻了 )。
两个类,一个 Connection 管理 PDO 连接(支持多数据库),一个 QuickQuery 用来快速执行数据库操作(不用在 PDO 和 PDOStatement 之间来回折腾)
不用下载,在线就能看完。
use Persistence\DbAccess; // 在框架初始化的地方添加连接信息 DbAccess\Connection::add( 'default', 'sqlite', '/db/mydb.sqlite', null, null, false ); // 下面是使用 $conn = DbAccess\Connection::instance('default'); // 查询 $query = new DbAccess\QuickQuery($conn); $query->prepare('select :name as name')->execute(array(':name'=>'tonyseek')); // 对象直接作为迭代器产生数据数组 foreach($query as $i) { var_dump($i); } // 如果有偏执的话,输出响应之前手动断开连接 DbAccess\Connection::disconnectAll();
<?php namespace Persistence\DbAccess; use PDO, ArrayObject, DateTime; use LogicException, InvalidArgumentException; /** * 快捷查询通道 * * @version 0.3 * @author tonyseek * @link http://www.php.cn/ * @license http://www.php.cn/ * @copyright StuCampus Development Team, Shenzhen University * */ class QuickQuery implements \IteratorAggregate { /** * 数据库连接 * * @var \Persistence\DbAccess\Connection */ private $connection = null; /** * PDO Statement * * @var PDOStatement */ private $stmt = null; /** * 被检查参数集 * * @var array */ private $checkedParams = array(); /** * 构造查询通道 * * @param \Persistence\DbAccess\Connection $connection 数据库连接 */ public function __construct(Connection $connection) { $this->connection = $connection; } /** * 预编译 SQL 语句 * * @param string $sqlCommand SQL语句 * @return \Persistence\DbAccess\QuickQuery */ public function prepare($sqlCommand) { // 从连接获取 PDO, 并对 SQL 语句执行 prepare, 产生 PDO Statement $this->stmt = $this->connection->getPDO()->prepare($sqlCommand); // 修改 PDO Statement 模式为关联数组数据 $this->stmt->setFetchMode(PDO::FETCH_ASSOC); // 返回方法链 return $this; } /** * 执行数据查询 * * @throws PDOException * @return \Persistence\DbAccess\QuickQuery */ public function execute($params = array()) { $stmt = $this->getStatement(); // 参数检查 $diff = array_diff($this->checkedParams, array_keys($params)); if (count($this->checkedParams) && count($diff)) { throw new InvalidArgumentException('缺少必备参数:'.implode(' | ', $diff)); } // 将 PHP 数据类型对应到数据库数据类型 foreach($params as $key => $value) { $type = null; switch(true) { case is_int($value): $type = PDO::PARAM_INT; break; case is_bool($value): $type = PDO::PARAM_BOOL; break; case ($value instanceof DateTime): $type = PDO::PARAM_STR; $value = $value->format(\DateTime::W3C); break; case is_null($value): $type = PDO::PARAM_NULL; break; default: $type = PDO::PARAM_STR; } $stmt->bindValue($key, $value, $type); } $stmt->execute(); $this->checkedParams = array(); // 清空参数检查 return $this; } /** * 获取 Statement 对象 * * 返回对象可以被绑定参数重新执行, 也可以被当作迭代器遍历获取数据。 * * @return \PDOStatement */ public function getStatement() { if (!$this->stmt) { throw new LogicException('SQL语句应该先被 QuickQuery.prepare 预处理'); } return $this->stmt; } /** * getStatement 方法的替代名 * * 实现 PHP 标准库 中的 IteratorAggregate 接口, 外部可以直接将本对象作为迭代器遍 * 历。和 getStatment 唯一不同之处, 是本方法不会抛出 LogicException 异常。如果 * 没有事先使用 prepare 和 execute, 会返回一个空迭代器。 * * @return Traversable */ public function getIterator() { try { return $this->getStatement(); } catch (LogicException $ex) { return new \ArrayObject(); } } /** * 设置查询参数检查 * * 通过此处导入的被检查查询参数, 如果没有得到赋值, 则查询时会抛出 LogicException 异常。 * * @param array $params * @return \Persistence\DbAccess\QuickQuery */ public function setParamsCheck(array $params) { $this->checkedParams = $params; return $this; } /** * 将结果集转换为数组 * * @return array */ public function toArray() { return iterator_to_array($this->getStatement()); } /** * 获取最后一个插入结果(或序列)的 ID * * @param string $name * @return int */ public function getLastInsertId($name=null) { return $this->connection->getPDO()->lastInsertId($name); } }
<?php namespace Persistence\DbAccess; use InvalidArgumentException, BadMethodCallException; use PDO, PDOException; /** * 连接工厂,提供全局的PDO对象,并管理事务。 * * @version 0.3 * @author tonyseek * @link http://www.php.cn/ * @license http://www.php.cn/ * @copyright StuCampus Development Team, Shenzhen University * */ final class Connection { /** * Connector 实例集合 * * @var array */ static private $instances = array(); /** * 数据库驱动名 * * @var string */ private $driver = ''; /** * 数据库连接字符串(Database Source Name) * * @var string */ private $dsn = ''; /** * PDO 实例 * * @var \PDO */ private $pdo = null; /** * 用户名 * * @var string */ private $username = ''; /** * 密码 * * @var string */ private $password = ''; /** * 是否开启持久连接 * * @var bool */ private $isPersisten = false; /** * 是否开启仿真预编译 * * @var bool */ private $isEmulate = false; /** * 是否在事务中 * * @var bool */ private $isInTransation = false; /** * 私有构造函数,阻止外部使用 new 操作符实例化 */ private function __construct(){} /** * 生产 Connector 实例(多例) * * @param string $name * @return \StuCampus\DataModel\Connector */ static public function getInstance($name = 'default') { if (!isset(self::$instances[$name])) { // 如果访问的实例不存在则抛出错误异常 throw new InvalidArgumentException("[{$name}] 不存在"); } return self::$instances[$name]; } /** * 断开所有数据库实例的连接 */ static public function disconnectAll() { foreach (self::$instances as $instance) { $instance->disconnect(); } } /** * 添加数据库 * * 向实例群添加 Connector * * @param string $name 标识名 * @param string $driver 驱动名 * @param string $dsn 连接字符串 * @param string $usr 数据库用户名 * @param string $pwd 数据库密码 * @param bool $emulate 仿真预编译查询 * @param bool $persisten 是否持久连接 */ static public function registry($name, $driver, $dsn, $usr, $pwd, $emulate = false, $persisten = false) { if (isset(self::$instances[$name])) { // 如果添加的实例名已经存在则抛出异常 throw new BadMethodCallException("[{$name}] 已被注册"); } // 实例化自身,并推入数组中 self::$instances[$name] = new self(); self::$instances[$name]->dsn = $driver . ':' . $dsn; self::$instances[$name]->username = $usr; self::$instances[$name]->password = $pwd; self::$instances[$name]->driver = $driver; self::$instances[$name]->isPersisten = (bool)$persisten; self::$instances[$name]->isEmulate = (bool)$emulate; } /** * 获取 PHP Database Object * * @return \PDO */ public function getPDO() { if (!$this->pdo) { // 检查 PDO 是否已经实例化,否则先实例化 PDO $this->pdo = new PDO($this->dsn, $this->username, $this->password); // 错误模式为抛出 PDOException 异常 $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // 开启查询缓存 $this->pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, $this->isEmulate); // 开启持久连接 $this->pdo->setAttribute(PDO::ATTR_PERSISTENT, $this->isPersisten); } return $this->pdo; } /** * 获取数据库驱动名 * * @return string */ public function getDriverName() { return $this->driver; } /** * 开始事务 */ public function transationBegin() { $this->isInTransation = $this->getPDO()->beginTransaction(); } /** * 提交事务 */ public function transationCommit() { if ($this->isInTransation) { $this->getPDO()->commit(); } else { trigger_error('transationBegin 应该先于 transationCommit 调用'); } } /** * 回滚事务 * @return bool */ public function transationRollback() { if ($this->isInTransation) { $this->getPDO()->rollBack(); } else { trigger_error('transationBegin 应该先于 transationRollback 调用'); } } /** * 连接是否在事务中 * * @return bool */ public function isInTransation() { return $this->isInTransation; } /** * 在事务中执行回调函数 * * @param function $callback 匿名函数或闭包函数 * @param bool $autoRollback 异常发生时是否自动回滚 * @throws \PDOException * @return bool */ public function transationExecute($callback, $autoRollback = true) { try { // 开始事务 $this->transationBegin(); // 调用回调函数 if (is_callable($callback)) { $callback(); } else { throw new InvalidArgumentException('$callback应该为回调函数'); } // 提交事务 return $this->transationCommit(); } catch(PDOException $pex) { // 如果开启了自动回滚, 则捕捉到 PDO 异常时先回滚再抛出 if ($autoRollback) { $this->transationRollback(); } throw $pex; } } /** * 安全地断开数据库连接 */ public function disconnect() { if ($this->pdo) { // 检查 PDO 是否已经实例化,是则设置为null $this->pdo = null; } } /** * 阻止克隆 */ public function __clone() { trigger_error('被阻止的 __clone 方法, Connector 是单例类'); } }