登录  /  注册

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

PHPz
发布: 2017-04-04 14:23:05
原创
1169人浏览过

Connector.php

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

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

<?php class Connector {
    // 数据库地址前缀,常见的有mysql,slqlsrv,odbc等等等
    private $driver = &#39;mysql&#39;;
    // 数据库地址
    private $host = &#39;localhost&#39;;
    // 数据库默认名称, 设置为静态是因为有切换数据库的需求
    private static $db = &#39;sakila&#39;;
    // 数据库用户名
    private $username = &#39;root&#39;;
    // 数据库密码
    private $password = &#39;&#39;;
    // 当前数据库连接
    protected $connection;
    // 数据库连接箱,切换已存在的数据库连接不需要重新通信,从这里取即可
    protected static $container = [];

    // PDO默认属性配置,具体请自行查看文档
    protected $options = [
        PDO::ATTR_CASE => PDO::CASE_NATURAL,
        PDO::ATTR_ERRMODE =&gt; PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_ORACLE_NULLS =&gt; PDO::NULL_NATURAL,
        PDO::ATTR_STRINGIFY_FETCHES =&gt; false,
    ];
}
登录后复制

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

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

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

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

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

      function construct() {
          // 如果从未连接过该数据库, 那就新建连接
          if(empty(self::$container[self::$db])) $this-&gt;connect();
          // 反之, 从$container中提取, 无需再次通信
          $this-&gt;connection = self::$container[self::$db];
      }
    登录后复制

接下来两个函数式配合着用的,单看可能会懵逼, 配合例子单步调试

$a = new Connector();

$bindValues = [
    'PENELOPE',
    'GUINESS'
];

dd($a-&gt;read('select * from actor where first_name = ? and last_name = ?', $bindValues));
登录后复制

返回值

array (size=1)
  0 =&gt; 
    object(stdClass)[4]
      public 'actor_id' =&gt; string '1' (length=1)
      public 'first_name' =&gt; string 'PENELOPE' (length=8)
      public 'last_name' =&gt; string 'GUINESS' (length=7)
      public 'last_update' =&gt; 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-&gt;connection-&gt;prepare($sql);
          // 将附带参数带入pdo实例
          // $bindings = ['PENELOPE', 'GUINESS']
          $this-&gt;bindValues($statement, $bindings);
          // 执行
          $statement-&gt;execute();
          // 返回所有合法数据, 以Object对象为数据类型
          return $statement-&gt;fetchAll(PDO::FETCH_OBJ);
      }
    登录后复制
  • bindValues - 将附带参数带入pdo实例

          // 从例子中可以看出, 我用在预处理的变量为?, 这是因为pdo的局限性, 有兴趣可以在评论区讨论这个问题
      public function bindValues($statement, $bindings) {
          // $bindings = ['PENELOPE', 'GUINESS']
          // 依次循环每一个参数
          foreach ($bindings as $key =&gt; $value) {
              // $key = 0/1
              // $value = 'PENELOPE'/'GUINESS'
              $statement-&gt;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-&gt;connection-&gt;prepare($sql);
          $this-&gt;bindValues($statement, $bindings);
          return $statement-&gt;execute();
      }
    登录后复制
  • delete - 删除数据

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

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

      // pdo自带,只是稍微封装
      public function lastInsertId() {
          $id = $this-&gt;connection-&gt;lastInsertId();
          return empty($id) ? null : $id;
      }
    登录后复制

过于高级复杂的SQL语句可能无法封装, 因此准备了可直接用RAW query通信数据库的两个函数

  • exec - 适用于增删改

      public function exec($sql) {
          return $this-&gt;connection-&gt;exec($sql);
      }
    登录后复制
  • query - 适用于读

      public function query($sql) {
          $q = $this-&gt;connection-&gt;query($sql);
          return $q-&gt;fetchAll(PDO::FETCH_OBJ);
      }
    登录后复制

将数据库事务相关的函数封装起来, 直白所以没有注释

        public function beginTransaction() {
        $this-&gt;connection-&gt;beginTransaction();
        return $this;
    }

    public function rollBack() {
        $this-&gt;connection-&gt;rollBack();
        return $this;
    }

    public function commit() {
        $this-&gt;connection-&gt;commit();
        return $this;
    }

    public function inTransaction() {
        return $this-&gt;connection-&gt;inTransaction();
    }
登录后复制

完整代码

<?php class Connector {
    // 数据库地址前缀,常见的有mysql,slqlsrv,odbc等等等
    private $driver = &#39;mysql&#39;;
    // 数据库地址
    private $host = &#39;localhost&#39;;
    // 数据库默认名称, 设置为静态是因为有切换数据库的需求
    private static $db = &#39;sakila&#39;;
    // 数据库用户名
    private $username = &#39;root&#39;;
    // 数据库密码
    private $password = &#39;&#39;;
    // 当前数据库连接
    protected $connection;
    // 数据库连接箱,切换已存在的数据库连接不需要重新通信,从这里取即可
    protected static $container = [];

    // PDO默认属性配置,具体请自行查看文档
    protected $options = [
        PDO::ATTR_CASE => PDO::CASE_NATURAL,
        PDO::ATTR_ERRMODE =&gt; PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_ORACLE_NULLS =&gt; PDO::NULL_NATURAL,
        PDO::ATTR_STRINGIFY_FETCHES =&gt; false,
    ];

    function construct() {
        // 如果从未连接过该数据库, 那就新建连接
        if(empty(self::$container[self::$db])) $this-&gt;connect();
        // 反之, 从$container中提取, 无需再次通信
        $this-&gt;connection = self::$container[self::$db];
    }

    // 生成DSN连接串
    protected function buildConnectString() {
        return "$this-&gt;driver:host=$this-&gt;host;dbname=".self::$db;
    }

    // 连接数据库
    public function connect() {
        try {
            // 连接数据库,生成pdo实例, 将之赋予$connection,并存入$container之中
            self::$container[self::$db] = $this-&gt;connection = new PDO($this-&gt;buildConnectString(), $this-&gt;username, $this-&gt;password, $this-&gt;options);

            // 返回数据库连接
            return $this-&gt;connection;
        } catch (Exception $e) {
            // 若是失败, 返回原因
            dd($e-&gt;getMessage());
        }
    }

    // 切换数据库
    public function setDatabase($db) {
        self::$db = $db;
        return $this;
    }

    // 读取数据
    public function read($sql, $bindings) {
        // 将sql语句放入预处理函数
        $statement = $this-&gt;connection-&gt;prepare($sql);
        // 将附带参数带入pdo实例
        $this-&gt;bindValues($statement, $bindings);
        // 执行
        $statement-&gt;execute();
        // 返回所有合法数据, 以Object对象为数据类型
        return $statement-&gt;fetchAll(PDO::FETCH_OBJ);
    }

    // 将附带参数带入pdo实例
    public function bindValues($statement, $bindings) {
        // 依次循环每一个参数
        foreach ($bindings as $key =&gt; $value) {
            $statement-&gt;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-&gt;connection-&gt;prepare($sql);
        $this-&gt;bindValues($statement, $bindings);
        return $statement-&gt;execute();
    }

    // 删除数据
    public function delete($sql, $bindings) {
        $statement = $this-&gt;connection-&gt;prepare($sql);
        $this-&gt;bindValues($statement, $bindings);
        return $statement-&gt;execute();
    }

    // 增加数据
    public function create($sql, $bindings) {
        $statement = $this-&gt;connection-&gt;prepare($sql);
        $this-&gt;bindValues($statement, $bindings);
        $statement-&gt;execute();
        return $this-&gt;lastInsertId();
    }

    // 返回新增id, 如果有
    public function lastInsertId() {
        $id = $this-&gt;connection-&gt;lastInsertId();
        return empty($id) ? null : $id;
    }

    // 适用于增删改
    public function exec($sql) {
        return $this-&gt;connection-&gt;exec($sql);
    }

    // 适用于读
    public function query($sql) {
        $q = $this-&gt;connection-&gt;query($sql);
        return $q-&gt;fetchAll(PDO::FETCH_OBJ);
    }

    public function beginTransaction() {
        $this-&gt;connection-&gt;beginTransaction();
        return $this;
    }

    public function rollBack() {
        $this-&gt;connection-&gt;rollBack();
        return $this;
    }

    public function commit() {
        $this-&gt;connection-&gt;commit();
        return $this;
    }

    public function inTransaction() {
        return $this-&gt;connection-&gt;inTransaction();
    }
}
登录后复制

本期疑问

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

以上就是如何写一个属于自己的数据库封装(2)的详细内容,更多请关注php中文网其它相关文章!

智能AI问答
PHP中文网智能助手能迅速回答你的编程问题,提供实时的代码和解决方案,帮助你解决各种难题。不仅如此,它还能提供编程资源和学习指导,帮助你快速提升编程技能。无论你是初学者还是专业人士,AI智能助手都能成为你的可靠助手,助力你在编程领域取得更大的成就。
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
关于CSS思维导图的课件在哪? 课件
凡人来自于2024-04-16 10:10:18
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

Copyright 2014-2024 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号