如何寫一個屬于自己的數據庫封裝(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 分享