[TOC]
## 命名規范
[【官方文檔】](http://www.hmoore.net/manual/thinkphp5/118007)
ThinkPHP5遵循PSR-2命名規范和PSR-4自動加載規范,并且注意如下規范:
### 目錄和文件
* 目錄使用小寫+下劃線;
* 類庫、函數文件統一以`.php`為后綴;
* 類的文件名均以命名空間定義,并且命名空間的路徑和類庫文件所在路徑一致;
* 類文件采用駝峰法命名(首字母大寫),其它文件采用小寫+下劃線命名;
* 類名和類文件名保持一致,統一采用駝峰法命名(首字母大寫);
### 函數和類、屬性命名
* 函數的命名使用小寫字母和下劃線(小寫字母開頭)的方式,例如 `get_client_ip`;
* 類的命名采用駝峰法(首字母大寫),例如 `User`、`UserType`,默認不需要添加后綴,例如`UserController`應該直接命名為`User`;
* 方法的命名使用駝峰法(首字母小寫),例如 `getUserName`;
* 屬性的命名使用駝峰法(首字母小寫),例如 `tableName`、`instance`;
* 以雙下劃線“__”打頭的函數或方法作為魔術方法,例如 `__call` 和` __autoload`;
### 常量和配置
* 常量以大寫字母和下劃線命名,例如 `APP_PATH`和 `THINK_PATH`;
* 配置參數以小寫字母和下劃線命名,例如 `url_route_on` 和`url_convert`;
### 數據表和字段
* 數據表和字段采用小寫加下劃線方式命名,并注意字段名不要以下劃線開頭
例如 `think_user` 表和 `user_name`字段,不建議使用駝峰和中文作為數據表字段命名。
### 應用類庫命名空間規范
應用類庫的根命名空間統一為app(不建議更改,可以設置`app_namespace`配置參數更改,V5.0.8版本開始使用`APP_NAMESPACE`常量定義);
例如:`app\index\controller\Index`和`app\index\model\User`。
## 模型對象
### 模型的基本CURD操作
| 用法 | Db類 | 模型(動態) | 模型(靜態)| 說明|
| --- | --- | --- | --- | --- |
| 創建 | insert | save | create | save(動態):返回影響的記錄數<br />create(靜態):返回模型對象實例|
| 更新 | update | save | update | save :更新數據,返回影響的記錄數<br />update:更新數據(靜態),返回模型對象實例 |
| 讀取單個 | find | find | get | get:查詢單個記錄,返回模型對象實例<br />find:查詢單個記錄,返回模型對象實例 |
| 讀取多個 | select | select | all | all:根據主鍵查詢多個記錄,返回包含模型對象實例的數組或者數據集<br />select:根據條件查詢多個記錄,返回包含模型對象實例的數組或者數據集 |
| 刪除 | delete | delete | destroy | delete:刪除當前數據,返回影響的記錄數<br />destroy:刪除指定數據(靜態),返回影響的記錄數 |
注意事項:
1. 模型類可以直接調用Db類的所有方法;
2. 模型類和Db類的查詢返回類型是完全不同的,即便是調用同一個方法查詢;
3. 模型類封裝的靜態方法本質上還是調用的動態方法,只是為了方便不同的需求場景;
4. 模型對象的查詢操作盡量使用靜態方法調用;
>[danger] 在模型的刪除功能設計的時候,應該盡量用軟刪除替代實際的刪除,一方面是為了避免數據丟失,一方面也是為了性能考慮(數據庫的刪除操作會導致重建索引,數據量越大影響越大)。
### 數據集(`collection`對象)
模型的單個數據查詢返回的都是模型對象實例,但查詢多個數據的時候默認返回的是一個包含模型對象實例的數組。
框架提供了一個Collection數據集對象來進行統一的模型的對象化操作,替代默認的數組數據集更好的封裝自己的數據處理和業務邏輯。
有兩種方式可以設置,
1. 全局設置數據庫的配置參數(默認設置為array):
~~~php
// 設置數據集返回類型
'resultset_type' => 'collection',
~~~
2. 在模型類中添加屬性設置
~~~php
// 設置模型的數據集返回類型
protected $resultSetType = 'collection';
~~~
該設置僅僅影響設置的模型中的查詢結果,如果需要多個模型或者全部模型支持,可以使用繼承或者使用第一種數據庫配置方式。
設置數據集對象后,查詢多個數據的方法(包括Db類的`select`和模型類的`all`方法)返回的結果類型就會變成`think\model\Collection`對象實例。
數據集對象和普通的二維數組在使用上的一個最大的區別就是數據是否為空的判斷,
~~~php
// 二維數組的數據集判斷數據為空
$resultSet = User::all();
if (empty($resultSet)) {
echo '數據集為空';
}
//數據集對象的判斷數據為空
$resultSet = User::all();
if ($resultSet->isEmpty()) {
echo '數據集為空';
}
//通用判斷數據為空
$resultSet = User::all();
if (0 == count($resultSet)) {
echo '數據集為空';
}
~~~
其它操作的區別就是一個是對象的方法操作,一個是數組函數的操作,下面是數據集對象的方法和數組函數的對應關系:
| 作用| 數據集方法 | 數組函數 |
| --- | --- | --- |
| 合并數據 | merge | array_merge|
| 比較數據差集 | diff | array_diff|
| 交換數組中的鍵和值 | flip | array_flip|
| 比較數組交集 | intersect | array_intersect|
| 返回鍵名 | keys | array_keys|
| 最后元素出棧 | pop| array_pop|
| 數組迭代簡化 | reduce | array_reduce|
| 數據反序 | reverse | array_reverse|
| 首個元素出棧 | shift | array_shift|
| 開頭插入元素 | unshift | array_unshift|
| 元素回調 | each | ---|
| 過濾元素 | filter | array_filter|
| 返回指定列 | column | array_column|
| 元素排序 | sort | array_sort|
| 打亂元素 | shuffle | shuffle|
| 截取部分元素 | slice | array_slice|
| 元素分割 | chunk | array_chunk|
| 轉換數組 | toArray | ---|
可以自定義數據集的返回對象,然后在里面封裝其它的方法。
一般自定義的數據集對象建議繼承`think\model\Collection`,然后在模型中設置`resultSetType`屬性值為自定義查詢類的類名。
~~~php
// 設置模型的數據集返回類型
protected $resultSetType = 'app\common\Collection';
~~~
總結下數據集的優勢:
* 數據更對象化;
* 關聯操作更方便;
* 數據集本身可以單獨定義獨立的業務方法;
### 自定義查詢(`get`方法`all`方法)
~~~php
// 查詢單個記錄
User::get(['name' => 'thinkphp']);
// 查詢數據集(閉包查詢條件)
User::all(function ($query) {
$query->where('id', '>', 0)
->limit(10)
->order('id desc');
});
// 刪除數據
User::destroy(['status' => 0]);
User::destroy(function ($query) {
$query->where('id', 'in', [1, 2, 3]);
});
~~~
>[danger] `get`、`all`以及`destroy`方法的參數用法記住如下原則,
> 1. 如果是數字、字符串或者普通數組都表示一個或者多個主鍵,
> 2. 如果是索引數組則表示查詢條件,
> 3. 閉包則支持查詢條件以外的其它鏈式操作方法。
> 4. 對于get方法的參數最好做一次非null檢查,否則查詢的就會是第一個數據(V5.0.8+已經改進,不需要檢查是否為null了)。
### 查詢范圍(`scope`前綴方法)
對于一些常用的查詢條件,我們可以事先定義好,以便快速調用,這個事先定義的查詢條件方法有一個統一的前綴`scope`,我們稱之為查詢范圍。例如在`User`模型中定義如下查詢范圍
~~~php
<?php
namespace app\index\model;
use think\Model;
class User extends Model
{
// email查詢
protected function scopeEmail($query)
{
$query->where('email', 'thinkphp@qq.com');
}
// status查詢
protected function scopeStatus($query)
{
$query->where('status', 1);
}
}
~~~
現在可以直接使用
~~~php
$users = User::scope('email,status')->select();
//或者
$users = User::scope('email')->scope('status')->select();
~~~
生成的SQL語句為
~~~sql
SELECT * FROM `user` WHERE `email` = 'thinkphp@qq.com' AND `status` = 1
~~~
查詢范圍之外仍然可以使用額外的查詢條件,例如:
~~~php
$users = User::scope('email,status')
->where('nickname', 'like', '%think%')
->order('id desc')
->select();
~~~
>[danger] 查詢范圍方法必須首先被調用
查詢范圍方法支持額外的參數,例如`scopeEmail`方法改為:
~~~php
// email查詢
protected function scopeEmail($query, $email = '')
{
$query->where('email', $email);
}
//然后,使用下面的方式調用即可(帶參數調用的時候每次只能調用一個查詢范圍):
$list = User::scope('email', 'thinkphp@qq.com')->select();
~~~
>[info] 查詢范圍的方法的第一個參數必須是查詢對象,并且支持多個額外參數。
### 全局查詢范圍(`base`方法)
查詢范圍有一個特殊的方法`base`,一旦在模型中定義了`base`方法后,無需顯式調用scope方法,系統會在每次查詢的時候自動調用。
~~~php
<?php
namespace app\index\model;
use think\Model;
class User extends Model
{
// 全局查詢范圍
protected static function base($query)
{
// 查詢狀態為1的數據
$query->where('status', 1);
}
// email查詢
protected function scopeEmail($query)
{
$query->where('email', 'thinkphp@qq.com');
}
}
~~~
當使用下面的查詢操作
~~~php
User::get(1);
User::scope('email')->select();
~~~
最后生成的SQL語句分別是:
~~~sql
SELECT * FROM `user` WHERE `status` = 1 AND `id` = 1 LIMIT 1
SELECT * FROM `user` WHERE `status` = 1 AND `email` = 'thinkphp@qq.com'
~~~
無論是什么查詢都會默認帶上全局查詢范圍中的條件。
可以臨時關閉全局查詢范圍進行查詢
~~~php
// 關閉全局查詢范圍
User::useGlobalScope(false)->get(1);
~~~
>[info] 查詢范圍方法中不僅支持where方法,任何查詢構造器的方法都可以被支持。
### 軟刪除
軟刪除的作用就是把數據加上刪除標記,而不是真正的物理刪除,同時也便于需要的時候進行數據的恢復。因為在實際項目中,對數據頻繁使用刪除操作會導致性能問題,因此不推薦直接物理刪除數據,而是用軟刪除(邏輯刪除)替代。
**1. 模型啟用軟刪除功能**
要使用軟刪除功能,需要引入`SoftDelete trait`,例如`User`模型按照下面的定義就可以使用軟刪除功能:
~~~php
<?php
namespace app\index\model;
use think\Model;
use traits\model\SoftDelete;
class User extends Model
{
use SoftDelete;
}
~~~
>[danger] 為了配合軟刪除功能,需要在數據表中添加`delete_time`字段,ThinkPHP5的軟刪除功能使用時間戳類型(數據表默認值為`Null`,MySQL中默認值為`NULL`),用于記錄數據的刪除時間。
**2. 數據表中指定軟刪除功能的標記字段**
如果軟刪除標記字段名稱不是`delete_time`的話,需要添加屬性定義:
~~~
<?php
namespace app\index\model;
use think\Model;
use traits\model\SoftDelete;
class User extends Model
{
use SoftDelete;
protected $deleteTime = 'delete_field_name';
}
~~~
>[info] 可以用類型轉換指定軟刪除字段的類型。
> 建議數據表的所有時間字段統一使用autoWriteTimestamp屬性規范時間類型(支持datetime、date、timestamp以及integer)。
~~~php
<?php
namespace app\index\model;
use think\Model;
use traits\model\SoftDelete;
class User extends Model
{
use SoftDelete;
protected $autoWriteTimestamp = 'datetime';
protected $deleteTime = 'delete_field_name';
}
~~~
**3. 軟刪除與物理刪除**
定義好模型,并在模型中按前2步啟用軟刪除功能,就可以使用靜態`destroy`或動態`delete`方法進行軟刪除:
~~~php
// 軟刪除
User::destroy(1);
// 真實刪除
User::destroy(1,true);
$user = User::get(1);
// 軟刪除
$user->delete();
// 真實刪除
$user->delete(true);
~~~
是將MySQL數據庫中的字段`delete_time`值設為由`NULL`設為時間戳。
**4. 恢復軟刪除的記錄**
定義好模型,并在模型中按前2步啟用軟刪除功能,就可以使用`restore()`方法恢復軟刪除的記錄:
~~~php
//軟刪除的恢復
$user->restore(['id'=>1]);
~~~
`restore($where=[])`方法需要的是與查詢方法類似的where條件數組,執行成功返回的是恢復的記錄數。
是將MySQL數據庫中的字段`delete_time`值設為`NULL`。
**5. 軟刪除與查詢**
默認情況下查詢的數據不包含軟刪除數據,如果需要包含軟刪除的數據,可以使用下面的方式查詢:
~~~php
User::withTrashed()->find();
User::withTrashed()->select();
~~~
如果僅僅需要查詢軟刪除的數據,可以使用:
~~~php
User::onlyTrashed()->find();
User::onlyTrashed()->select();
~~~
如果查詢條件比較復雜,尤其是某些特殊情況下使用`OR`查詢條件會把軟刪除數據也查詢出來,可以使用閉包查詢的方式解決,如下:
~~~php
User::where(function($query) {
$query->where('id', '>', 10)
->whereOr('name', 'like', 'think');
})->select();
~~~
>[danger] 使用閉包查詢條件會在查詢條件兩邊添加括號,從而不會和軟刪除條件產生混淆或者沖突。
如果模型定義了base基礎查詢(全局查詢范圍,框架在查詢時自動調用),請確保添加軟刪除的基礎查詢條件,例如:
~~~php
protected static function base($query)
{
// 添加軟刪除條件
$query->whereNull('delete_time')
// 添加額外的基礎查詢條件
->where('id','>',0);
}
~~~
### 字段過濾 (`allowField`方法)
模型類提供了`allowField`方法用于在數據寫入操作的時候設置字段過濾,從而避免數據庫因為字段不存在而報錯。
~~~php
// 獲取當前用戶對象
$user = User::get(request()->session('user_id'));
// 只允許更新用戶的nickname和address數據
$user->allowField(['nickname', 'address'])
->data(requst()->param(), true)
->save();
~~~
如果僅僅是希望去除數據表之外的字段,可以使用
~~~php
// 只允許更新數據表字段數據
$user->allowField(true)
->data(requst()->param(), true)
->save();
~~~
如果使用的是模型的靜態方法(如create和update方法)進行數據寫入的話,可以使用下面的方式進行字段過濾。
~~~php
User::create(request()->param(), ['nickname', 'address']);
User::update(request()->param(), ['id' => 1], ['nickname', 'address']);
~~~
同樣可以傳入`true`表示過濾非數據表字段
~~~php
User::create(request()->param(), true);
User::update(request()->param(), ['id' => 1], true);
~~~
## 問題
### 1. 應用公共文件(common.php)如何自動加載,從而實現在應用中直接使用文件中定義的常量和函數?
### 2. 模塊公共文件(module/common.php)中定義的常量和函數如何使用?
- WebAPP
- Linux Command
- 入門
- 處理文件
- 查找文件單詞
- 環境
- 聯網
- Linux
- Linux目錄配置標準:FHS
- Linux文件與目錄管理
- Linux賬號管理與ACL權限設置
- Linux系統資源查看
- 軟件包管理
- Bash
- Daemon/Systemd
- ftp
- Apache
- MySQL
- Command
- Replication
- mysqld
- remote access
- remark
- 限制
- PHP
- String
- Array
- Function
- Class
- File
- JAVA
- Protocals
- http
- mqtt
- IDE
- phpDesigner
- eclipse
- vscode
- Notepad++
- WebAPI
- Javasript
- DOM
- BOM
- Event
- Class
- Module
- Ajax
- Fetch
- Promise
- async/await
- Statements and declarations
- Function
- Framwork
- jQurey
- Types
- Promise
- BootStrap
- v4
- ThinkPHP5
- install
- 定時任務
- CodeIgniter
- React.js
- node.js
- npm
- npm-commands
- npm-folder
- package.json
- Docker and private modules
- module
- webpack.js
- install
- configuration
- package.json
- entry
- modules
- plugins
- Code Splitting
- loaders
- libs
- API
- webpack-cli
- Vue.js
- install
- Compile
- VueAPI
- vuex
- vue-router
- vue-devtools
- vue-cli
- vue-loader
- VDOM
- vue-instance
- components
- template
- Single-File Components
- props
- data
- methods
- computed
- watch
- Event-handling
- Render Func
- remark
- 案例學習
- bootstrap-vue
- modal
- fontAwesome
- Hosting Font Awesome Yourself
- using with jquery
- using with Vue.js
- HTML
- CSS
- plugins
- Chart.js
- D3.js
- phpSpreadSheet
- Guzzle
- Cmder
- Git
- git命令
- git流程
- Postman
- Markdown
- Regular Expressions
- PowerDesigner
- 附錄1-學習資源