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

本期要点

深入了解php函数的各种辅助函数 php核心语法:函数

理解什么是php函数函数, …$var, PHP5.6新特性介绍

php函数函数的用法 PHP: compact – Manual

php函数函数的用法 PHP: list – Manual

PHPphp函数

开始之前

本期说的是SQL中的查询语句, 由于复杂程度和多个类之间的关联性不是Connector篇那么简单, 故此, 这一回需要一口气讲解Builder类, Grammar类, 还有php函数类, 当然, 只是查询部分


Builder.php

  • 请求构建器, 所有类之间的桥梁

<?php  /**  * 请求构建器  */  class Builder {      // 连接数据库, Connector类      protected $connector;        // 生成SQL语法,Grammar类      protected $grammar;        // 连接的Model, Model类      protected $model;        // SQL查询语句中条件的值      // 虽然列出了全部, 但本教程只实现了where,其余的因为懒(理直气壮),请自行实现, 逻辑和where函数大致      protected $bindings = [          'select' => [],          'join'   => [],          'where'  => [],          'having' => [],          'order'  => [],          'union'  => [],      ];        // select 语法想要查看的字段      public $columns;        // 过滤重复值      public $distinct = false;        // 需要查询的表      public $from;        // 所有join 语法      public $joins;        // 所有where 语法      public $wheres;        // group 语法      public $groups;        // having 语法      public $havings;        // order by 语法      public $orders;        // 限制数据库返回的数据量, limit语法      public $limit;        // 需要略过的数据量, offset语法      public $offset;        // 数据写保护, 开启后该条数据无法删除或改写      public $writeLock = false;

接下来是函数

  • _construct – 生成实例后第一步要干嘛

      function construct() {        // 新建两个实例        // 如果已经理解Connector的原理后自然明白这个Connector实例已经联通了数据库        $this->connector = new Connector;        $this->grammar = new Grammar;    }
  • select – 选择想看到的column, 默认为全部, 即 ‘*’

    public function select($columns = ['*']) {        // $columns只能存入数组, 所以需要判定, 如果不是, 将所有参数合成一个数组再存入        // 这是一个更人性化的设定, 用户可以选择以下两种调用方式        // select(['first_name', 'last_name']), 以数组的方式        // select('first_name', 'last_name'), 以参数的方式        // 最后一点, 你可以发现所有函数最后都会存入对应的Builder属性中        // 这和你在做饭前先处理材料是同一个道理, 也就是预处理        $this->columns = is_array($columns) ? $columns : func_get_args();        return $this;    }
  • distinct – 过滤重复值

    public function distinct() {        // 开启过滤        $this->distinct = true;        return $this;    }
  • from – 设置表名

      public function from($table) {        $this->from = $table;        return $this;    }
  • join – 连接两个表的join语法, 默认为inner join

    /**     * @param  string $table   需要连接的副表名     * 为什么主键和外键可以单个或数组呢     * 原因是join语法可以on多个键     * @param  string/array $foregin 外键     * @param  string/array $primary 主键     * @param  string $type    连接方式, 默认inner     * @return Builder          返回Builder实例     */    public function join($table, $foregin , $primary, $type = 'inner') {        // 判定外键变量的数据类型        if(is_array($foregin)) {            // 如果是数组, 循环加上副表名在前头            foreach($foregin as &$f)                $f = $table.".".$f;        }else {            // 反之, 不需循环直接加            $foregin = $table.".".$foregin;        }          // 与$foreign的逻辑同理        if(is_array($primary)) {            foreach($primary as &$p)                $p = $this->from.".".$p;        }else {            $primary = $this->from.".".$primary;        }          // 将所有经过处理的参数收入$joins待用        $this->joins[] = (object)[            'from' => $this->from,            'table' => $table,            'foregin' => $foregin,            'primary' => $primary,            'type' => $type        ];          // 返回Builder实例        return $this;    }
  • join的各种变形, 只实现常见的三种join, 其余请自行添加

    // 所有逻辑同join(), 不过这是left join    public function leftJoin($table, $foregin , $primary) {        return $this->join($table, $foregin , $primary, 'left');    }      // 所有逻辑同join(), 不过这是right join    public function rightJoin($table, $foregin , $primary) {        return $this->join($table, $foregin , $primary, 'right');    }
  • addBinding – 储存各种sql条件所附带的值

    /**     * @param string/array $value 字段匹配的值     * @param string $type  条件类型, 默认为where, 具体查看$bindings     */    public function addBinding($value, $type = 'where') {        // 如果$type并不是$bindings的键, 跳出错误        if (!array_key_exists($type, $this->bindings))             throw new InvalidArgumentException("Invalid binding type: {$type}.");          // 如果$value是数组,将其与之前存入的值整合为一维数组        if (is_array($value))             $this->bindings[$type] = array_values(array_merge($this->bindings[$type], $value));        // 反之, 直接存入最后一位即可        else            $this->bindings[$type][] = $value;          // 返回Builder实例        return $this;    }
  • where – sql中的条件, where语法

where()有两种不同的调用方式
接下来多个函数都有两种调用方式, 请从之后的代码逻辑中自行领悟
以参数的方式, 默认为’=’

Actor::select('first_name', 'last_name')    ->where('first_name', 'NICK')    ->where('last_name','!=', 'WAHLBERG')    ->first()

以数组的方式, 这方式有局限性, 仅能匹配 字段等于值 的情况

Actor::select('first_name', 'last_name')    ->where(['first_name'=> 'NICK', 'last_name'=> 'WAHLBERG'])    ->first()

接下来看代码

public function where($column, $operator = null, $value = null, $boolean = 'and') {          // 判定$column是否为数组          if (is_array($column)) {              // 如果是数组, 循环再调用本函数,where()              foreach ($column as $key => $value)                   $this->where($key, "=", $value, $boolean);          }else {              // 反之, 判定参数数量和$value是否为空, 如果为真,这意味着用户省略了'=',自动添加              if(func_num_args() == 2 || is_null($value)) list($operator, $value) = ['=', $operator];                // 最简单原始的条件查询, 所以$type值为Basic              $type = "Basic";              // 将处理过的条件存入$wheres              $this->wheres[] = compact('type', 'column', 'operator', 'value', 'boolean');              // 将字段需要匹配的值存入$bindings中的where              $this->addBinding($value, 'where');          }            // 返回Builder实例          return $this;      }
  • where的各种变形

    // 所有逻辑同where(), 不过这是or where    public function orWhere($column, $operator = null, $value = null) {        return $this->where($column, $operator, $value, 'or');    }      /**     * where in 语法, 字段匹配多个值     * @param  string  $column  字段     * @param  array  $values  一组字段需匹配的值     * @param  string  $boolean 默认为and     * @param  boolean $not     默认为假, 真为排除所有$value里的数据     * @return Builder           返回Builder实例     */    public function whereIn($column, $values, $boolean = 'and', $not = false) {        // 判定条件查询的类型, false = where in ($value),true = where not in ($value)        $type = $not ? 'NotIn' : 'In';        // 将条件存入$wheres        $this->wheres[] = compact('type', 'column', 'values', 'boolean');        // 循环将字段需要匹配的值存入$bindings中的where        foreach ($values as $value)             $this->addBinding($value, 'where');          // 返回Builder实例        return $this;    }      // 所有逻辑同whereIn(), 不过这是or where in    public function orWhereIn($column, $values) {        return $this->whereIn($column, $values, 'or');    }      // 所有逻辑同whereIn(), 不过这是and where not in    public function whereNotIn($column, $values, $boolean = 'and') {        return $this->whereIn($column, $values, $boolean, true);    }      // 所有逻辑同whereNotIn(), 不过这是or where not in    public function orWhereNotIn($column, $values) {        return $this->whereNotIn($column, $values, 'or');    }      /**     * where $coulmn is null 语法, 搜索字段为空的数据     * @param  string  $column  字段     * @param  string  $boolean 默认为and     * @param  boolean $not     默认为假, 真为排除所有字段为空的数据     * @return Builder          返回Builder实例     */    public function whereNull($column, $boolean = 'and', $not = false) {        // 判定条件查询的类型, false = where $column is null,true = where $column is not null        $type = $not ? 'NotNull' : 'Null';        // 将条件存入$wheres        $this->wheres[] = compact('type', 'column', 'boolean');        // 返回Builder实例        return $this;    }      // 所有逻辑同whereNull(), 不过这是or where $column is null    public function orWhereNull($column) {        return $this->whereNull($column, 'or');    }      // 所有逻辑同whereNull(), 不过这是and where $column is not null    public function whereNotNull($column, $boolean = 'and') {        return $this->whereNull($column, $boolean, true);    }      // 所有逻辑同whereNotNull(), 不过这是or where $column is not null    public function orWhereNotNull($column) {        return $this->whereNotNull($column, 'or');    }
  • orderBy – order by 语句, 决定返回的数据排列

    /**     * @param  string/array $column    字段     * @param  string $direction 排序,默认为asc, 顺序     * @return Builder            返回Builder实例     */    public function orderBy($column, $direction = 'asc') {        // 局限性在于必须声明顺序或逆序        if(is_array($column)) {            foreach ($column as $key => $value)                 $this->orderBy($key, $value);        }else {            // 简单判定后直接存入$orders, $direction输入错误不跳错误直接选择顺序            $this->orders[] = [                'column' => $column,                'direction' => strtolower($direction) == 'desc' ? 'desc' : 'asc',            ];        }          // 返回Builder实例        return $this;    }

    辅助函数 – array_flatten

    这是我自己写的一个函数, 用于抚平php函数
    什么意思呢, 就是将多维数组整成一维数组

    function array_flatten(array $array) {    $return = array();    array_walk_recursive($array, function($a) use (&$return) {         $return[] = $a;     });    return $return;  }

    例子

    $a = array('this', 'is', array('a', 'multidimentional', array('array') ), 'to', 'make', 'the', 'tutotal', array('more', 'easier', 'to', 'understand') );  dd(array_flatten($a));

    返回

    array (size=13)  0 => string 'this' (length=4)  1 => string 'is' (length=2)  2 => string 'a' (length=1)  3 => string 'multidimentional' (length=16)  4 => string 'array' (length=5)  5 => string 'to' (length=2)  6 => string 'make' (length=4)  7 => string 'the' (length=3)  8 => string 'tutotal' (length=7)  9 => string 'more' (length=4)  10 => string 'easier' (length=6)  11 => string 'to' (length=2)  12 => string 'understand' (length=10)
  • groupBy – group by 语句, 整合数据

    /**     * @param  string/array $groups 字段     * @return Builder        返回Builder实例     */    public function groupBy(...$groups) {        if(empty($this->groups)) $this->groups = [];        $this->groups = array_merge($this->groups, array_flatten($groups));        // 返回Builder实例        return $this;    }
  • limit – 限制返回的数据量, sqlsrv的写法不同, 有兴趣知道的可以留言

      public function limit($value) {        // 如果$value大于零这条函数才生效        if ($value >= 0) $this->limit = $value;        return $this;    }      // limit函数的别名, 增加函数链的可读性    public function take($value) {        return $this->limit($value);    }
  • offset – 跳过指定的数据量, sqlsrv的写法不同, 有兴趣知道的可以留言

      public function offset($value) {        // 如果$value大于零这条函数才生效        if ($value >= 0) $this->offset = $value;        return $this;    }      // offset函数的别名, 增加函数链的可读性    public function skip($value) {        return $this->offset($value);    }
  • get – 读取数据库数据
    重头戏来了, 之前所有的函数都是返回Builder实例的,这意味着可再编辑
    这是一个总结, 将前端的函数链请求一并处理了

    // 返回一组数据库数据, 可以在这里设定想返回的字段, 但是select()的优先度最高    public function get($columns = ['*']) {        // 如果Builder的$columns依然为空, 那么就用该函数的$columns, 反之则使用select()所声明的字段        if (is_null($this->columns)) $this->columns = $columns;        // 如果Builder的$orders依然为空, 那么就默认第一个字段顺序        // 发现一个莫名的bug, 可能是我理解错了, 不加 order by 1数据返回竟然不是按照主键(第一个字段)排序        // 所以以防万一加一个默认        if (is_null($this->orders)) $this->orderBy(1);        // 将Grammar类生成的语句,和处理过的字段所对应的值,都交给Connector类, 让它与数据库进行通信,返回数据        // 注意这里的三个函数        // read() 不用说Connector篇介绍过了        // compileSelect()是用来编译生成查询语句        // getBindings()用来获取收在$bindings中条件的值, 下方会有说明        $results = $this->connector->read($this->grammar->compileSelect($this), $this->getBindings());        // 返回一组数据库数据,如果查询为空,返回空数组        // cast()下方会有说明        return $this->cast($results);    }      // get函数的别名, 增加函数链的可读性    public function all($columns = ['*']) {        return $this->get($columns);    }
  • getBindings – 返回所有$bindings中的值

      public function getBindings() {        // 抚平多维数组成一维数组后再返回        return array_flatten($this->bindings);    }
  • cast – 转化返回的数据类型为自身的Model子类
    在基本思路篇的最终效果小节有提到过数据的可操作性, 核心代码就是这里
    如果看不明白这里没关系, 暂时跳过, 等看完Model.php就能理解了(吧?)

      public function cast($results){        // 获取Model子类的名称        $class = get_class($this->model);        // 新建一个Model子类        $model = new $class();        // 如果获得的数据库数据是数组        if (gettype($results)=="array") {            $arr = [];            // 循环数据            foreach ($results as $result)                 // 再调用本函数                $arr[] = $this->cast($result);            // 返回经过转化的数据数组            return $arr;        // 如果获得的数据库数据是对象        }elseif(gettype($results)=="object"){            // 存入数据对象            $model->setData($results);            // 加入主键或unique key以实现数据的可操作性            // 如果表存在主键和返回的数据中有主键的字段            if($model->getIdentity() && isset($results->{$model->getIdentity()})) {                $model->where($model->getIdentity(), $results->{$model->getIdentity()});            // 如果表存在unique key和返回的数据中有unique key的字段            }elseif($model->getUnique() && array_check($model->getUnique(),$results)) {                foreach ($model->getUnique() as $key)                     $model->where($key, $results->$key);            // 改写和删除操作仅仅在符合以上两种条件其中之一的时候            // 反之, 开启写保护不允许改写            }else {                // 其实还可以考虑直接复制query                // 但变数太多干脆直接一棍子打死                $model->getBuilder()->writeLock = true;            }            // 返回该实例            return $model;        }        // 如果转化失败返回false        return false;    }
  • first – 仅取头一条数据, 所以返回的是对象, 而get返回的是数组,里头多条对象

    /**     * @param  array  $columns 如果Builder的$columns依然为空, 那么就用该函数的$columns, 反之则使用select()所声明的字段     * @return boolean/Model          查询为空返回false, 反之则返回附带数据的表类     */    public function first($columns = ['*']) {        $results = $this->take(1)->get($columns);        return empty($results) ? false : $results[0];    }
  • setModel – 设置Model实例

      public function setModel(Model $model) {        $this->model = $model;        return $this;    }

    告一段落, 接下来编译SQL语句, Grammar类


Grammar.php

  • 根据经过处理后存在Builder实例属性中的值进行编译

  • 编译是一部分一部分语法慢慢编译的, 最后在总结起来

<?php  /**  * 数据库语法生成      */  class Grammar {      // 构建查询语句所可能出现的各种SQL语法      // 注意, 它们的顺序是对应着各自在SQL语句中合法的位置      // sqlsrv略微不同      protected $selectComponents = [          'distinct',          'columns',          'from',          'joins',          'wheres',          'groups',          'orders',          'limit',          'offset',      ];
  • concatenate –  排除编译后可能存在空的值,然后连接整句SQL语句

      protected function concatenate($segments) {        return implode(' ', array_filter($segments, function ($value) {            return (string) $value !== '';        }));    }
  • compileSelect – 编译SQL查询语句

      // 还记得Builder->get()中的compileSelect()吗?    public function compileSelect(Builder $query) {        // concatenate()排除编译后可能存在空的值,然后连接整句SQL语句        // 去掉可能存在的前后端空格再返回        return trim($this->concatenate($this->compileComponents($query)));    }
  • compileComponents – 循环$selectComponents, 根据不同的语法局部编译对应的语句

      protected function compileComponents(Builder $query) {        $sql = [];        // 循环$selectComponents        foreach ($this->selectComponents as $component) {            // 如果Builder实例中对应的函数曾经被调用,那意味着对应的语法非空            if (!is_null($query->$component)) {                $method = 'compile'.ucfirst($component);                // 编译该语法并将之收入$sql                $sql[$component] = $this->$method($query, $query->$component);            }        }        // 返回$sql数组        return $sql;    }
  • compileDistinct – 编译distinct语句

      protected function compileDistinct(Builder $query, $distinct) {        return $distinct ? 'select distinct' : 'select';    }
  • compileLimit – 编译limit语句

      protected function compileLimit(Builder $query, $limit) {        return "limit $limit";    }
  • compileOffset – 编译offset语句

      protected function compileOffset(Builder $query, $offset) {        return "offset $offset";    }
  • compileColumns – 编译需查询的字段

      protected function compileColumns(Builder $query, $columns) {        return implode(', ', $columns);    }
  • compileFrom – 编译生成表名

      protected function compileFrom(Builder $query, $table) {        return 'from '.$table;    }
  • compileJoins – 编译join语句

      protected function compileJoins(Builder $query, $joins) {        $sql = [];        foreach ($joins as $join) {            // 如果存在多个副键和主键            if(is_array($join->foregin) && is_array($join->primary)) {                $on = [];                // 循环键的数量, 将之与对应的主键组合                for($i=0; $i<sizeof($join->foregin); $i++)                    $on[] = $join->foregin[$i]." = ".$join->primary[$i];                // 最后再将所有句子用and连接                $on = implode(' and ', $on);            } else {            //反之, 直接连接即可                $on = "$join->foregin = $join->primary";            }            // 附上join的类型和副表            $sql[] = trim("{$join->type} join {$join->table} on $on");        }          // 连接再返回        return implode(' ', $sql);    }
  • compileWheres – 编译where语句

      protected function compileWheres(Builder $query) {        $sql = [];        // 类似与compileComponents(), 循环Builder实例中的$wheres        foreach ($query->wheres as $where) {            // 根据不同的$type来进行编译            $method = "where{$where['type']}";            // 返回的部分语句先收入数组            $sql[] = $where['boolean'].' '.$this->$method($query, $where);        }        // 最后将$sql数组连接起来, 删掉最前面的and或or在返回        return 'where '.preg_replace('/and |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告一段落, 接下来是php函数, 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);    }

    魔术方法

  • callphp函数 – 如果找不到php函数函数的时候自动运行下面的逻辑

      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 – 在php函数的时候隐藏多余的信息, 只留下数据库返回的数据

      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是怎么解决php函数 2100个最大参数(bind)的问题吗? 源代码把我看蒙了

© 版权声明
THE END
喜欢就支持一下吧
点赞11 分享