盾怪网教程:是一个免费提供流行杀毒软件教程、在线学习分享的学习平台!

怎么写一个属于自己的数据库封装(3)

时间:2025/3/12作者:未知来源:盾怪网教程人气:

[摘要]or /i, , implode(" ", $sql), 1);}whereBasic - 编译最基本的where用法 protected function whereBasi...
or /i', '', implode(" ", $sql), 1); }
  • whereBasic - 编译最基本的where用法

      protected function whereBasic(Builder $query, $where) {
          // 检测$where[column]是否存在小数点
          // 是, 就意味着前缀已经附带了表名
          // 否, 为之后的字段添上表名
          // 因为join存在副表, 所以部分$where可能有附带表名, 这时候就不用添加了
          $table = !preg_match('/\./', $where['column']) ? $query->from."." : '';
          // 返回添上表名的字段,和表达式, 再一个问号
          // 为何使用问号而不是:变量名? 因为:变量名存在太多局限性,不能标点符号,不能数字开头
          return $table.$where['column'].' '.$where['operator'].' ?';
      }
  • whereIn - 编译where in用法

      protected function whereIn(Builder $query, $where) {
          // 检测$where[column]是否存在小数点, 同理whereBasic()
          $table = !preg_match('/\./', $where['column']) ? $query->from."." : '';
          // 有多少个匹配值那就连接多少个问号
          $values = implode(', ', array_fill(0, sizeof($where['values']), '?'));
          // 返回where in 语句
          return $table.$where['column'].' in ('.$values.')';
      }
  • whereNotIn - 编译where not in用法

      protected function whereNotIn(Builder $query, $where) {
          // 检测$where[column]是否存在小数点, 同理whereBasic()
          $table = !preg_match('/\./', $where['column']) ? $query->from."." : '';
          // 有多少个匹配值那就连接多少个问号
          $values = implode(', ', array_fill(0, sizeof($where['values']), '?'));
          // 返回where not in 语句
          return $table.$where['column'].' not in ('.$values.')';
      }
  • whereNull - 编译where null用法

      protected function whereNull(Builder $query, $where) {
          // 检测$where[column]是否存在小数点, 同理whereBasic()
          $table = !preg_match('/\./', $where['column']) ? $query->from."." : '';
          // 返回where is null 语句
          return $table.$where['column'].' is null';
      }
  • whereNotNull - 编译where not null用法

      protected function whereNotNull(Builder $query, $where) {
          // 检测$where[column]是否存在小数点, 同理whereBasic()
          $table = !preg_match('/\./', $where['column']) ? $query->from."." : '';
          // 返回where is not null 语句
          return $table.$where['column'].' is not null';
      }
  • compileGroups - 编译group by语句

      protected function compileGroups(Builder $query, $groups) {
          // 连接$groups, 返回group by语句
          return 'group by '.implode(', ', $groups);
      }
  • compileOrders - 编译order by语句

      protected function compileOrders(Builder $query, $orders) {
          // 连接每一个$order与其$direction, 然后返回order by语句
          return 'order by '.implode(', ', array_map(function ($order) {
              return $order['column'].' '.$order['direction'];
          }, $orders));
      }

    Grammar告一段落, 接下来是入口文件, Model类, 一个魔术世界


  • Model.php

    • 数据库表的依赖对象

    • 作为数据的出口, 数据就在这里进行修饰

    • 各种魔术方法用得飞起, 使用之前请先理解魔术方法是什么

    <?php
    /**
    * 入口文件, 数据库表的父类
    */
    class Model {
        // SQL命令构建器, Builder类
        protected $builder;
    
        // 数据库返回的数据存在这里
        protected $data;
    
        // 数据库表名, 选填, 默认为类名
        protected $table;
    
        // 主键, 二选一($unique)
        protected $identity;
    
        // unique key, 二选一($identity)
        protected $unique;
    • getTable - 获取数据库表名, 没有设置返回false

        public function getTable() {
            return isset($this->table) ? $this->table : false;
        }
    • getIdentity - 获取主键名, 没有返回假

        public function getIdentity() {
            return isset($this->identity) ? $this->identity : false;
        }
    • getUnique - 获取unique key名, 没有返回假

        public function getUnique() {
            // 检测是否存在unique key, 不存在返回假, 存在就在检查是否数组, 不是就装入数组再返回
            return isset($this->unique) ? is_array($this->unique) ? $this->unique : [$this->unique] : false;
        }
    • check - 检查必须预设的实例属性

        public function check() {
            // 如果数据库表的名称和Model的子类相同,可以选择不填,默认直接取类的名称
            if(!$this->getTable()) 
                $this->table = get_class($this);
      
            // 跳出提醒必须设置$identity或$unique其中一项
            if(!$this->getIdentity() && !$this->getUnique())
                throw new Exception('One of $identity or $unique should be assigned in Model "'.get_called_class().'"');
      
        }
    • set/getBuilder - 设置或读取Builder实例

      // 设置Builder实例
        public function setBuilder(Builder $builder) {
            $this->builder = $builder;
            return $this;
        }
      
        // 获取Builder实例
        public function getBuilder() {
            return $this->builder;
        }
    • setData - 设置数据库数据

        public function setData($data) {
            $this->data = $data;
            return $this;
        }
    • construct - 创建实例后的第一步

        function construct() {
            // 检查设定是否正确
            $this->check();
            // 新建一个Builder实例
            $this->setBuilder(new Builder);
            // 设置构建器的主表名称
            $this->getBuilder()->from($this->table);
            // 将Model实例带入Builder
            $this->getBuilder()->setModel($this);
        }

      魔术方法

    • callStatic - 如果找不到静态函数的时候自动运行下面的逻辑

        static public function callStatic($method, $args = null) {
            // 这是一个伪静态, 创建一个实例
            $instance = new static;
            // 在$instance->builder之中, 寻找函数$method, 并附上参数$args
            return call_user_func_array([$instance->builder, $method], $args);
        }
    • call - 如果找不到函数的时候自动运行下面的逻辑

        public function call($method, $args) {
            // 在$this->builder之中, 寻找函数$method, 并附上参数$args
            return call_user_func_array([$this->builder, $method], $args);
        }
    • debugInfo - 在调试的时候隐藏多余的信息, 只留下数据库返回的数据

        public function debugInfo() {
            // 也不懂算不算bug, 该方法强制要求返回的数据类型必须是array数组
            // 但是就算我强行转换(casting)后返回的数据依然是对象(object)
            return (array)$this->data;
        }
    • get - 当调用对象的属性时, 强制调用这个魔术方法

        // 为了避免局外人可以访问Model类的属性
        // 为了避免对象属性和表的字段名字相同
        public function get($field) {
            // 如果调用的属性是Model类内的逻辑
            // 直接返回该属性的值
            if(get_called_class()==="Model") 
                return $this->$field;
            // 反之, 则检查$data内是否存在该属性, 没有的话跳出错误
            if(!isset($this->data->$field)) 
                throw new Exception("column '$field' is not exists in table '$this->table'");
            // 如果存在,由于返回的数据都是存在$data里, 所以要这样调用
            return $this->data->$field;
        }
    • set - 当想修改的对象属性时, 强制调用这个魔术方法

        public function set($field, $value) {
            // 如果调用的属性是Model类内的逻辑
            // 直接赋值该属性
            if(get_called_class()==="Model")
                return $this->$field = $value;
            // 反之, 则检查$data内是否存在该属性, 没有的话跳出错误
            if(!isset($this->data->$field)) 
                throw new Exception("column '$field' is not exists in table '$this->table'");
      
            // 如果存在,由于返回的数据都是存在$data里, 所以要这样赋值
            return $this->data->$field = $value;
        }

      进阶的Buider类封装没错, 我又把Builder(微)封装了

    • find - 使用主键查寻数据

      /**
         * @param  int $id 主键
         * @return Model subclass     返回一个Model的子类数据
         */
        public static function find($id) {
            // 这是一个伪静态, 创建一个实例
            $self = new static;
      
            // 该函数只适用于设置了主键的表, 如果没有设置, 跳出错误
            if(!$self->getIdentity()) 
                throw new Exception("Table's identity key should be assgined");
      
            return $self->where($self->identity, $id)->first();
        }

      还有更多, 看心情更...


    本期疑问

    1.) 缺少的Builder函数如果有人愿意提供例子就好了, 进阶复杂的语句那就更好了, 直接写然后再分享给我那就最好了
    2.) 有些函数或结构可能没有效率或者白白添加服务器压力, 但我写的顺了可能没看见, 请指出
    3.) 有人能告诉我laravel是怎么解决pdo 2100个最大参数(bind)的问题吗? 源代码把我看蒙了

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


    学习教程快速掌握从入门到精通的SQL知识。



    关键词:如何写一个属于自己的数据库封装(3)




    Copyright © 2012-2018 盾怪网教程(http://www.dunguai.com) .All Rights Reserved 网站地图 友情链接

    免责声明:本站资源均来自互联网收集 如有侵犯到您利益的地方请及时联系管理删除,敬请见谅!

    QQ:1006262270   邮箱:kfyvi376850063@126.com   手机版