## 創建core/database/model/Model.php
```
<?php
namespace core\database\model;
class Model
{
// 綁定的數據庫連接
protected $connection;
protected $table; // 表
protected $paimaryKey; // 主鍵
protected $timestamps = true; // 是否自動維護時間字段
/*
為什么要分開兩個屬性?
$orginal 原的數據
$attriubte 原數據的復制版 用戶只能修改這個 !
然后跟$original相比較 得出用戶修改的數據字段
*/
protected $original;
protected $attribute;
public function __construct()
{
// 給當前模型綁定一個數據庫連接
$this->connection = \App::getContainer()->get('db')->connection(
$this->connection
);
}
// 獲取表名稱 沒有表名稱 就返回 模型(小寫)+s
public function getTable()
{
if( $this->table)
return $this->table;
$class_name = get_class($this);
$class_arr = explode('\\',$class_name);
$table = lcfirst(end(
$class_arr
));
return $table .'s';
}
public function setOriginalValue($key, $val)
{
if(! $this->original)
$this->original = new \stdClass();
$this->original->$key = $val;
}
public function setAttribute($key, $val)
{
if(! $this->attribute)
$this->attribute = new \stdClass();
$this->attribute->$key = $val;
}
// 見最上面的說明
public function __set($key, $value)
{
$this->setAttribute($key, $value);
}
// 屬性 同步 original
public function syncOriginal()
{
$this->attribute = $this->original;
}
/**
* 返回用戶改過的數據
* @return array
* @example ['id' => 3,'user_id' => '3']
*/
public function diff()
{
$diff = [];
if( $this->attribute == $this->original) // 沒改變
return $diff;
foreach ($this->original as $origin_key => $origin_val)
if( $this->attribute->$origin_key != $origin_val) // 改變了
$diff[$origin_key] = $this->attribute->$origin_key;
return $diff;
}
public function __get($name)
{
return $this->attribute->$name;
}
// 托管到 __call
//因此: User::where() 與 (new User)->where() 是一樣的
public static function __callStatic($method, $args)
{
return (new static())->$method(...$args);
}
public function __call($method, $args)
{
return (new Builder(
$this->connection->newBuilder()
))
->setModel($this)
->$method(...$args);
}
}
````
## 創建core/database/model/Builder.php
```
<?php
namespace core\database\model;
class Builder
{
protected $query;
protected $model;
public function __construct($query)
{
$this->query = $query;
}
public function setModel(Model $model)
{
$this->model = $model;
return $this;
}
public function __call($method, $args)
{
$this->query->$method(...$args);
return $this;
}
public function get($columns = ['*'])
{
if(! is_array($columns))
$columns = func_get_args();
$this->query->columns = $columns;
$this->query->table( $this->model->getTable());
$sql = $this->query->toSql();
return $this->bindModel(
$this->query->runSql($sql)
);
}
// 數據映射模式 把數據映射到模型
//模型的本質: 每條數據都是一個模型(對象)
protected function bindModel($datas)
{
if(! is_array($datas))
$datas[] = $datas;
$models = [];
foreach ($datas as $data){ // 多少條數據就多少個模型
$model = clone $this->model; // 原型模式
foreach ($data as $key => $val)
$model->setOriginalValue($key, $val);
$model->syncOriginal(); // 把attriubtes = orginal
$models[] = $model;
}
return $models;
}
}
```
## 編輯app/User.php 繼承模型基礎類

## 運行
由于每條數據都是一個類,所以可以調用方法。


- 前言
- 基礎篇
- 1. 第一步 創建框架目錄結構
- 2. 引入composer自動加載
- 3. php自動加載 (解釋篇)
- 4. 創建容器 注冊樹模式
- 5. 關于psr規范解釋
- 6. 關于"容器" "契約" "依賴注入" (解釋篇)
- 7. 添加函數文件helpers.php
- 8. 初始化請求(Request)
- 9. 響應 (Response)
- 10. 路由一 (路由組實現)
- 11. 路由二 (加入中間件)
- 12. 配置信息 (類似laravel)
- 13. 數據庫連接 (多例模式)
- 14. 查詢構造器 (query builder)
- MVC實現
- M 模型實現 (數據映射 + 原型 模式)
- C 控制器實現 + 控制器中間件
- V 視圖實現 (Laravel Blade 引擎)
- V 視圖切換成 ThinkPhp 模板 引擎)
- 其他輪子
- 日志
- 自定義異常 (異常托管)
- 單元測試 (phpunit)
- 替換成swoole的http服務器
- 協程上下文解決request問題
- qps測試
- 發布到packagist.org