最新文章专题视频专题问答1问答10问答100问答1000问答2000关键字专题1关键字专题50关键字专题500关键字专题1500TAG最新视频文章推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37视频文章20视频文章30视频文章40视频文章50视频文章60 视频文章70视频文章80视频文章90视频文章100视频文章120视频文章140 视频2关键字专题关键字专题tag2tag3文章专题文章专题2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章专题3
当前位置: 首页 - 科技 - 知识百科 - 正文

如何写一个属于自己的数据库封装(2)

来源:动视网 责编:小采 时间:2020-11-09 09:03:20
文档

如何写一个属于自己的数据库封装(2)

如何写一个属于自己的数据库封装(2):Connector.php负责与数据库通信,增删改读(CRUD)首先, 建一个Connector类, 并且设置属性<php class Connector { // 数据库地址前缀,常见的有mysql,slqlsrv,odbc等等等 private $driver = 'mysql'; /
推荐度:
导读如何写一个属于自己的数据库封装(2):Connector.php负责与数据库通信,增删改读(CRUD)首先, 建一个Connector类, 并且设置属性<php class Connector { // 数据库地址前缀,常见的有mysql,slqlsrv,odbc等等等 private $driver = 'mysql'; /


Connector.php

  • 负责与数据库通信,增删改读(CRUD)

  • 首先, 建一个Connector类, 并且设置属性

    <?php
    class Connector {
     // 数据库地址前缀,常见的有mysql,slqlsrv,odbc等等等
     private $driver = 'mysql';
     // 数据库地址
     private $host = 'localhost';
     // 数据库默认名称, 设置为静态是因为有切换数据库的需求
     private static $db = 'sakila';
     // 数据库用户名
     private $username = 'root';
     // 数据库密码
     private $password = '';
     // 当前数据库连接
     protected $connection;
     // 数据库连接箱,切换已存在的数据库连接不需要重新通信,从这里取即可
     protected static $container = [];
    
     // PDO默认属性配置,具体请自行查看文档
     protected $options = [
     PDO::ATTR_CASE => PDO::CASE_NATURAL,
     PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
     PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL,
     PDO::ATTR_STRINGIFY_FETCHES => false,
     ];
    }

    以上代码配合注释应该可以理解了所以不多解释了,直接进入函数

  • buildConnectString - 就是生成DSN连接串, 非常直白

     protected function buildConnectString() {
     return "$this->driver:host=$this->host;dbname=".self::$db;
     }
     // "mysql:host=localhost;dbname=sakila;"
  • connect - 连接数据库

     public function connect() {
     try {
     // 连接数据库,生成pdo实例, 将之赋予$connection,并存入$container之中
     self::$container[self::$db] = $this->connection = new PDO($this->buildConnectString(), $this->username, $this->password, $this->options);
     // 返回数据库连接
     return $this->connection;
     } catch (Exception $e) {
     // 若是失败, 返回原因
     // 还记得dd()吗?这个辅助函数还会一直用上
     dd($e->getMessage());
     }
     }
  • setDatabase - 切换数据库

     public function setDatabase($db) {
     self::$db = $db;
     return $this;
     }
  • _construct - 生成实例后第一步要干嘛

     function construct() {
     // 如果从未连接过该数据库, 那就新建连接
     if(empty(self::$container[self::$db])) $this->connect();
     // 反之, 从$container中提取, 无需再次通信
     $this->connection = self::$container[self::$db];
     }
  • 接下来两个函数式配合着用的,单看可能会懵逼, 配合例子单步调试

    $a = new Connector();
    
    $bindValues = [
     'PENELOPE',
     'GUINESS'
    ];
    
    dd($a->read('select * from actor where first_name = ? and last_name = ?', $bindValues));

    返回值

    array (size=1)
     0 => 
     object(stdClass)[4]
     public 'actor_id' => string '1' (length=1)
     public 'first_name' => string 'PENELOPE' (length=8)
     public 'last_name' => string 'GUINESS' (length=7)
     public 'last_update' => string '2006-02-15 04:34:33' (length=19)
  • read - 读取数据

     public function read($sql, $bindings) {
     // 将sql语句放入预处理函数
     // $sql = select * from actor where first_name = ? and last_name = ?
     $statement = $this->connection->prepare($sql);
     // 将附带参数带入pdo实例
     // $bindings = ['PENELOPE', 'GUINESS']
     $this->bindValues($statement, $bindings);
     // 执行
     $statement->execute();
     // 返回所有合法数据, 以Object对象为数据类型
     return $statement->fetchAll(PDO::FETCH_OBJ);
     }
  • bindValues - 将附带参数带入pdo实例

     // 从例子中可以看出, 我用在预处理的变量为?, 这是因为pdo的局限性, 有兴趣可以在评论区讨论这个问题
     public function bindValues($statement, $bindings) {
     // $bindings = ['PENELOPE', 'GUINESS']
     // 依次循环每一个参数
     foreach ($bindings as $key => $value) {
     // $key = 0/1
     // $value = 'PENELOPE'/'GUINESS'
     $statement->bindValue(
     // 如果是字符串类型, 那就直接使用, 反之是数字, 将其+1
     // 这里是数值, 因此返回1/2
     is_string($key) ? $key : $key + 1,
     // 直接放入值
     // 'PENELOPE'/'GUINESS'
     $value,
     // 这里直白不多说
     // PDO::PARAM_STR/PDO::PARAM_STR
     is_int($value) ? PDO::PARAM_INT : PDO::PARAM_STR
     );
     }
     }

    所以懂了吗_( :3」∠)

  • update - 改写数据

     // 与read不同的地方在于, read返回数据, update返回boolean(true/false)
     public function update($sql, $bindings) {
     $statement = $this->connection->prepare($sql);
     $this->bindValues($statement, $bindings);
     return $statement->execute();
     }
  • delete - 删除数据

    // 与update一样, 分开是因为方便日后维护制定
     public function delete($sql, $bindings) {
     $statement = $this->connection->prepare($sql);
     $this->bindValues($statement, $bindings);
     return $statement->execute();
     }
  • create - 增加数据

    // 返回最新的自增ID, 如果有
     public function create($sql, $bindings) {
     $statement = $this->connection->prepare($sql);
     $this->bindValues($statement, $bindings);
     $statement->execute();
     return $this->lastInsertId();
     }
  • lastInsertId - 返回新增id, 如果有

     // pdo自带,只是稍微封装
     public function lastInsertId() {
     $id = $this->connection->lastInsertId();
     return empty($id) ? null : $id;
     }
  • 过于高级复杂的SQL语句可能无法封装, 因此准备了可直接用RAW query通信数据库的两个函数

  • exec - 适用于增删改

     public function exec($sql) {
     return $this->connection->exec($sql);
     }
  • query - 适用于读

     public function query($sql) {
     $q = $this->connection->query($sql);
     return $q->fetchAll(PDO::FETCH_OBJ);
     }
  • 将数据库事务相关的函数封装起来, 直白所以没有注释

     public function beginTransaction() {
     $this->connection->beginTransaction();
     return $this;
     }
    
     public function rollBack() {
     $this->connection->rollBack();
     return $this;
     }
    
     public function commit() {
     $this->connection->commit();
     return $this;
     }
    
     public function inTransaction() {
     return $this->connection->inTransaction();
     }

    完整代码

    <?php
    class Connector {
     // 数据库地址前缀,常见的有mysql,slqlsrv,odbc等等等
     private $driver = 'mysql';
     // 数据库地址
     private $host = 'localhost';
     // 数据库默认名称, 设置为静态是因为有切换数据库的需求
     private static $db = 'sakila';
     // 数据库用户名
     private $username = 'root';
     // 数据库密码
     private $password = '';
     // 当前数据库连接
     protected $connection;
     // 数据库连接箱,切换已存在的数据库连接不需要重新通信,从这里取即可
     protected static $container = [];
    
     // PDO默认属性配置,具体请自行查看文档
     protected $options = [
     PDO::ATTR_CASE => PDO::CASE_NATURAL,
     PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
     PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL,
     PDO::ATTR_STRINGIFY_FETCHES => false,
     ];
    
     function construct() {
     // 如果从未连接过该数据库, 那就新建连接
     if(empty(self::$container[self::$db])) $this->connect();
     // 反之, 从$container中提取, 无需再次通信
     $this->connection = self::$container[self::$db];
     }
    
     // 生成DSN连接串
     protected function buildConnectString() {
     return "$this->driver:host=$this->host;dbname=".self::$db;
     }
    
     // 连接数据库
     public function connect() {
     try {
     // 连接数据库,生成pdo实例, 将之赋予$connection,并存入$container之中
     self::$container[self::$db] = $this->connection = new PDO($this->buildConnectString(), $this->username, $this->password, $this->options);
    
     // 返回数据库连接
     return $this->connection;
     } catch (Exception $e) {
     // 若是失败, 返回原因
     dd($e->getMessage());
     }
     }
    
     // 切换数据库
     public function setDatabase($db) {
     self::$db = $db;
     return $this;
     }
    
     // 读取数据
     public function read($sql, $bindings) {
     // 将sql语句放入预处理函数
     $statement = $this->connection->prepare($sql);
     // 将附带参数带入pdo实例
     $this->bindValues($statement, $bindings);
     // 执行
     $statement->execute();
     // 返回所有合法数据, 以Object对象为数据类型
     return $statement->fetchAll(PDO::FETCH_OBJ);
     }
    
     // 将附带参数带入pdo实例
     public function bindValues($statement, $bindings) {
     // 依次循环每一个参数
     foreach ($bindings as $key => $value) {
     $statement->bindValue(
     // 如果是字符串类型, 那就直接使用, 反之是数字, 将其+1
     is_string($key) ? $key : $key + 1,
     // 直接放入值
     $value,
     // 这里直白不多说
     is_int($value) ? PDO::PARAM_INT : PDO::PARAM_STR
     );
     }
     }
    
     // 改写数据
     public function update($sql, $bindings) {
     // 与read不同的地方在于, read返回数据, update返回boolean(true/false)
     $statement = $this->connection->prepare($sql);
     $this->bindValues($statement, $bindings);
     return $statement->execute();
     }
    
     // 删除数据
     public function delete($sql, $bindings) {
     $statement = $this->connection->prepare($sql);
     $this->bindValues($statement, $bindings);
     return $statement->execute();
     }
    
     // 增加数据
     public function create($sql, $bindings) {
     $statement = $this->connection->prepare($sql);
     $this->bindValues($statement, $bindings);
     $statement->execute();
     return $this->lastInsertId();
     }
    
     // 返回新增id, 如果有
     public function lastInsertId() {
     $id = $this->connection->lastInsertId();
     return empty($id) ? null : $id;
     }
    
     // 适用于增删改
     public function exec($sql) {
     return $this->connection->exec($sql);
     }
    
     // 适用于读
     public function query($sql) {
     $q = $this->connection->query($sql);
     return $q->fetchAll(PDO::FETCH_OBJ);
     }
    
     public function beginTransaction() {
     $this->connection->beginTransaction();
     return $this;
     }
    
     public function rollBack() {
     $this->connection->rollBack();
     return $this;
     }
    
     public function commit() {
     $this->connection->commit();
     return $this;
     }
    
     public function inTransaction() {
     return $this->connection->inTransaction();
     }
    }

    本期疑问

    1.) 因为php本身的特性, 默认情况下运行完所有代码类会自行析构,pdo自动断联, 所以我没有disconnect(),让pdo断开连接, 不知这样是不是一种 bad practice?
    2.) 增加和改写数据的两个函数并不支持多组数据一次性加入,只能单次增该, 原因是我之前写了嫌太繁琐所以删了, 有心的童鞋可以提供方案

    文档

    如何写一个属于自己的数据库封装(2)

    如何写一个属于自己的数据库封装(2):Connector.php负责与数据库通信,增删改读(CRUD)首先, 建一个Connector类, 并且设置属性<php class Connector { // 数据库地址前缀,常见的有mysql,slqlsrv,odbc等等等 private $driver = 'mysql'; /
    推荐度:
    标签: 有一个 数据 如何
    • 热门焦点

    最新推荐

    猜你喜欢

    热门推荐

    专题
    Top