第2章 應(yīng)用Thinkphp6框架

2.1 ? ?上手Thinkphp6
2.1.1 ? ?介紹
ThinkPHP 是一款由國(guó)人開發(fā)的,免費(fèi),開源,輕量級(jí)的 PHP 開發(fā)框架。中文開發(fā)文檔齊全,社區(qū)活躍, 遇到問(wèn)題也可以較快獲取解決方案。
Thinkphp6 支持 PHP 的強(qiáng)類型, PSR 開發(fā)規(guī)范得了更廣泛的應(yīng)用。對(duì) Swoole 支持得到了優(yōu)化與提升,支持更多的 IDE 編輯器友好提示,對(duì)原生的語(yǔ)法進(jìn)行大量的精簡(jiǎn)。
環(huán)境要求:
PHP>=7.1.0
注意: 6.0 版本之后,必須通過(guò) Composer 方式安裝和更新,無(wú)法通過(guò) Git 下載安裝。
2.1.2 ? ?安裝
windows 下安裝 composer :
下載并且運(yùn)行 Composer-Setup.exe,它將安裝最新版本的 Composer ,并設(shè)置好系統(tǒng)的環(huán)境變量,因此你可以在任何目錄下直接使用 composer 命令。
建議使用國(guó)內(nèi)鏡像:
composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/
ThinkPHP6 穩(wěn)定版安裝:
composer create-project topthink/think tp
這里的 tp
項(xiàng)目名稱可以自行更改,這個(gè)目錄就是我們后面會(huì)經(jīng)常提到的應(yīng)用根目錄。
ThinkPHP6 開發(fā)版安裝:
composer create-project topthink/think=6.0.x-dev tp
安裝完成之后就可以通過(guò)域名訪問(wèn)新建的 ThinkPHP6 框架, 如果看到歡迎頁(yè)面。恭喜你,已經(jīng)完成 ThinkPHP6.0
的安裝 。
2.1.3 ? ?目錄介紹
www ?WEB部署目錄(或者子目錄)
├─app ? 應(yīng)用目錄
│ ?├─controller 控制器目錄
│ ?├─model ? ? ?模型目錄
│ ?├─ ... ? ? ? 更多類庫(kù)目錄
│ ?│
│ ?├─common.php 公共函數(shù)文件
│ ?└─event.php ?事件定義文件
│
├─config配置目錄
│ ?├─app.php ? ?應(yīng)用配置
│ ?└─...更多配置
│
├─view ?視圖目錄
├─route 路由定義目錄
│ ?├─route.php ?路由定義文件
│ ?└─ ...
│
├─publicWEB目錄(對(duì)外訪問(wèn)目錄)
│ ?├─index.php ?入口文件
│ ?└─router.php 快速測(cè)試文件
│
├─runtime ? ? ? 應(yīng)用的運(yùn)行時(shí)目錄(可寫,可定制)
├─composer.json composer 定義文件
└─think 命令行入口文件
核心目錄與文件 :
App 目錄
你的大部分應(yīng)用程序都位于 app
目錄中。默認(rèn)情況下,此目錄的命名空間為 App
,控制器、模型、路由、驗(yàn)證器等內(nèi)容都可以放在 app 目錄。
Config 目錄
config 目錄,顧名思義,包含應(yīng)用程序所有的配置文件。我們鼓勵(lì)你通讀這些文件,以便幫助你熟悉所有可用的選項(xiàng)。
View目錄
根目錄下面的 view 為全局的視圖目錄,如果 app 應(yīng)用下面沒 view 目錄, 默認(rèn)的視圖就會(huì)在這個(gè)目錄查找。
Route 目錄
根目錄下面 route 目錄未全局的路由目錄,如果為多應(yīng)用,推薦在對(duì)應(yīng)應(yīng)用下面創(chuàng)建 route 目錄。
Public 目錄
public
目錄包含了入口文件 index.php
,它是進(jìn)入應(yīng)用程序的所有請(qǐng)求的入口點(diǎn)。此目錄還包含了一些你的資源文件(如圖片、JavaScript 和 CSS )。
Runtime 目錄
應(yīng)用的運(yùn)行時(shí)目錄,日志以及上傳的文件默認(rèn)保存目錄。
2.2 ? ?Thinkphp6 請(qǐng)求與響應(yīng)
2.2.1 ? ?控制器
控制器是指按照預(yù)定順序改變程序,它是發(fā)布命令的 “ 決策機(jī)構(gòu) ”,即完成協(xié)調(diào)和指揮整個(gè)程序的操作。
訪問(wèn)控制器
域名/項(xiàng)目名/public/index.php/index/index
注意: 如果有域名,推薦根目錄為 public , 那么訪問(wèn)地址對(duì)應(yīng)為: 域名 /index.php/index/index , 偽靜態(tài)處理參考tp6官方手冊(cè)。
定義控制器 :
控制器文件通常放在 controller 下面,類名和文件名保持一致,并采用駝峰命名(首字母大寫)。
<?php
namespace app\controller;
class Login
{
? ?public function login()
? ?{
? ? ? return 'Hello World!';
? ?}
}
資源控制器(命令創(chuàng)建控制器):
#資源控制器 ?自帶一些常用的方法
php think make:controller News
#或者 ? plain為創(chuàng)建一個(gè)簡(jiǎn)單版的控制器(只有命名空間跟類名)
php think make:controller News ?--plain
渲染輸出 :
public function outPut()
{
? ?#htm格式輸出
? #return 'Hello World!';
? ?#json格式
? $data = ["hello"=>"world"];
? ?? return json($data);
? }
? #dump,halt調(diào)試變量輸出
? dump('hello');
? halt('halt是tp框架封裝的斷點(diǎn)調(diào)試,后面代碼不在執(zhí)行')
}
依賴注入 :
public function index(\think\Request $request)
{
? ?return $request->param('name');
}
靜態(tài)調(diào)用 :
public function index()
{
? ?return \think\facade\Request::param('name');
}
請(qǐng)求信息 :
可以通過(guò)請(qǐng)求對(duì)象獲取當(dāng)前請(qǐng)求的 控制器/操作名: 如查看當(dāng)前請(qǐng)求的控制器的方法是 Request::controller( )
方法含義controller
當(dāng)前請(qǐng)求的控制器名action
當(dāng)前請(qǐng)求的操作名method
獲取當(dāng)前請(qǐng)求方式
更多方法可以打開\think\Request類查看里面封裝的方法或者參考 Thinkphp 手冊(cè)
控制器重定向 :
完整地址重定向 :
return redirect('https://space.bilibili.com/546137543';);
站內(nèi)跳轉(zhuǎn)使用完整地址重定向 :
語(yǔ)法結(jié)構(gòu) :
return redirect ('/ 應(yīng)用名 / 控制器名 / 方法名 [/ 參數(shù) / 值 ]' );
控制器使用 :
核心控制器:框架核心 tink/Controller
6.0 取消了框架的核心控制器,提供了app\BaseController
,BaseController 是一個(gè)抽象類。
在Index控制器中, 可以看到 Index 控制器默認(rèn)繼承基礎(chǔ)控制器 BaseController 。
<?php
namespace app\controller;
use app\BaseController;
class Index extends BaseController
{
? ?public function index()
? ?{
? ? return ? 'index控制器 - index方法';
? ?}
}
訪問(wèn) Index 控制器 中的 index 方法 :

Index 繼承于 BaseController , 可以在index方法中 使用父類的 request 對(duì)象調(diào)用 param,get,post等方法獲取請(qǐng)求參數(shù) :
? ?public function index()
? ?{
? ? ? ?dump($this->request->param());
// ? ? ? ?dump($this->request->get());
? ?}
訪問(wèn)index方法時(shí)加入?yún)?shù)id與name:/index/index?id=113428497&name=nahida
輸出:
array:2[
????"id" => 113428497,
????"name" => "nahida"
]
其他獲取請(qǐng)求參數(shù)的方法 :
<?php
namespace app\controller;
use app\BaseController;
use app\Request;
class Index extends BaseController
{
? ?public function index(Request $request)
? ?{
? ? ? ?//通過(guò)依賴注入拿到 $request對(duì)象 調(diào)用param方法獲取參數(shù)
? ? ? ?$request->param('id');
? ? ? ?//通過(guò)門面模式 或者 在上面引入: use think\facade\Request;
? ? ? ?\think\facade\Request::param('id');
? ? ? ?//通過(guò)input 方法
? ? ? ?input('id');
? ? ? ?
? ? ? ?//通過(guò) ?request ?方法
? ? ? ?request()->param('id');
? ?}
}
注意: $this->request->param('name',1,'intval'); ?param 方法第一個(gè)參數(shù) 是獲取的參數(shù)名,第二個(gè)參數(shù)是默認(rèn)值,如果沒有name參數(shù),默認(rèn)就是1,intval 是參數(shù)轉(zhuǎn)換。以上各種獲取請(qǐng)求參數(shù)的方法 都可以這么用。
變量類型方法包括:

2.2.2 ? ?路由
要使用 Route
類注冊(cè)路由必須首先在路由定義文件開頭添加引用(項(xiàng)目根目錄下面 route 目錄,該目錄下面可以任意創(chuàng)建 php 文件為路由文件)
# 項(xiàng)目根目錄下面
use think\facade\Route;
# 注冊(cè)路由到News控制器的read操作(單應(yīng)用)
Route::rule('new/:id','News/read');
訪問(wèn) : http://serverName/new/5
#Route::快捷方法名('路由表達(dá)式', '路由地址');
#動(dòng)態(tài)變量 ? :變量 或者 <變量>
Route::get('new/<id>','News/read'); // 定義GET請(qǐng)求路由規(guī)則
Route::post('new/<id>','News/update'); // 定義POST請(qǐng)求路由規(guī)則
Route::put('new/:id','News/update'); // 定義PUT請(qǐng)求路由規(guī)則
Route::delete('new/:id','News/delete'); // 定義DELETE請(qǐng)求路由規(guī)則
Route::any('new/:id','News/read'); // 所有請(qǐng)求都支持的路由規(guī)則
注冊(cè)多個(gè)路由規(guī)則后,系統(tǒng)會(huì)依次遍歷注冊(cè)過(guò)的滿足請(qǐng)求類型的路由規(guī)則,一旦匹配到正確的路由規(guī)則后則開始執(zhí)行最終的調(diào)度方法,后續(xù)規(guī)則就不再檢測(cè)。
2.2.3 ? ?視圖
視圖功能由 \think\View
類配合視圖驅(qū)動(dòng)(也即模板引擎驅(qū)動(dòng))類一起完成,新版僅內(nèi)置了 PHP 原生模板引擎(主要用于內(nèi)置的異常頁(yè)面輸出),如果需要使用其它的模板引擎需要單獨(dú)安裝相應(yīng)的模板引擎擴(kuò)展。
composer require topthink/think-view
模板賦值 :
namespace app\controller;
use think\facade\View;
class Login
{
? ?public function test()
? ?{
View::assign('name','nahida');
View::assign(['age'=>5,'addr'=>'湖南長(zhǎng)沙']);
View::fetch(); ?#等同于View::fetch('test')或者View::fetch('login/test'),fetch方法在沒有參數(shù)的時(shí)候默認(rèn)在當(dāng)前應(yīng)用的view目錄查找當(dāng)前控制器/當(dāng)前方法名的視圖模板即login/test.html
? ?}
}
在模板中使用 :
在模板中輸出變量的方法很簡(jiǎn)單,只需要使用標(biāo)簽開始標(biāo)記和結(jié)束標(biāo)記包含, 默認(rèn)的開始和結(jié)束標(biāo)記為 { },如:
{$name}
模板編譯后的結(jié)果如下 :
<?php
echo htmlentities($name);
?>
這樣,運(yùn)行的時(shí)候就會(huì)在模板中顯示:nahida
2.3 ? ?Thinkphp6 數(shù)據(jù)庫(kù)操作
數(shù)據(jù)庫(kù)配置 :
return [
? ?'default' ? ?=> ? ?'mysql',
? ?'connections' ? ?=> ? ?[
'mysql' ? ?=> ? ?[
? ?// 數(shù)據(jù)庫(kù)類型
? ?'type'=> 'mysql',
? ?// 服務(wù)器地址
? ?'hostname' ? ?=> '127.0.0.1',
? ?// 數(shù)據(jù)庫(kù)名
? ?'database' ? ?=> 'nahida',
? ?// 數(shù)據(jù)庫(kù)用戶名
? ?'username' ? ?=> 'root',
? ?// 數(shù)據(jù)庫(kù)密碼
? ?'password' ? ?=> 'root',
? ?// 數(shù)據(jù)庫(kù)連接端口
? ?'hostport' ? ?=> '',
? ?// 數(shù)據(jù)庫(kù)連接參數(shù)
? ?'params' ? ? ?=> [],
? ?// 數(shù)據(jù)庫(kù)編碼默認(rèn)采用utf8
? ?'charset' ? ? => 'utf8',
? ?// 數(shù)據(jù)庫(kù)表前綴
? ?'prefix' ? ? ?=> 'tp_',
],
'demo' ? ?=> ? ?[
? ?// 數(shù)據(jù)庫(kù)類型
? ?'type'=> 'mysql',
? ?// 服務(wù)器地址
? ?'hostname' ? ?=> '127.0.0.1',
? ?// 數(shù)據(jù)庫(kù)名
? ?'database' ? ?=> 'demo',
? ?// 數(shù)據(jù)庫(kù)用戶名
? ?'username' ? ?=> 'root',
? ?// 數(shù)據(jù)庫(kù)密碼
? ?'password' ? ?=> 'root',
? ?// 數(shù)據(jù)庫(kù)連接端口
? ?'hostport' ? ?=> '',
? ?// 數(shù)據(jù)庫(kù)連接參數(shù)
? ?'params' ? ? ?=> [],
? ?// 數(shù)據(jù)庫(kù)編碼默認(rèn)采用utf8
? ?'charset' ? ? => 'utf8',
? ?// 數(shù)據(jù)庫(kù)表前綴
? ?'prefix' ? ? ?=> 'think_',
],
? ?],
];
默認(rèn)使用 connections 里面的 mysql 對(duì)應(yīng)的數(shù)據(jù)庫(kù),可以通過(guò)在模型里面指定 $connection 連接不同庫(kù),例如使用配置中demo對(duì)應(yīng)的庫(kù),只需要在模型類中申明 :
protected $connection = 'demo';
查詢 ( find,select,value,columns ) :
// table方法必須指定完整的數(shù)據(jù)表名
Db::table('think_user')->where('id', 1)->find();
最終生成的SQL語(yǔ)句可能是 :
SELECT * FROM `think_user` WHERE ?`id` = 1 LIMIT 1
$list = Db::table('think_user')->where('status', 1)->select();
# 返回某個(gè)字段的值
Db::table('think_user')->where('id', 1)->value('name');
# 返回?cái)?shù)組
Db::table('think_user')->where('status',1)->column('name');
# 指定id字段的值作為索引
Db::table('think_user')->where('status',1)->column('name', 'id');
新增數(shù)據(jù) ( save,insert,insertall ):
$data = ['foo' => 'bar', 'bar' => 'foo'];
Db::name('user')->save($data);
Db::name('user')->insert($data);
#批量新增
$data = [
? ?['foo' => 'bar', 'bar' => 'foo'],
? ?['foo' => 'bar1', 'bar' => 'foo1'],
? ?['foo' => 'bar2', 'bar' => 'foo2']
];
Db::name('user')->insertAll($data);
修改數(shù)據(jù) ( save,update ) :
Db::name('user')
? ?->save(['id' => 1, 'name' => 'thinkphp']);
#save方法會(huì)自動(dòng)判斷是新增數(shù)據(jù)還是更新數(shù)據(jù),主要是判斷數(shù)據(jù)中是否包含主鍵數(shù)據(jù)。
Db::name('user')
? ?->update(['id' => 1, 'name' => 'thinkphp']);
# 如果要更新的字段是數(shù)值類型,可以使用inc/dec方法自增或自減一個(gè)字段的值
# 比如score 字段加 1 ? inc第二個(gè)參數(shù)為自增步長(zhǎng)
Db::name('user')
? ?->where('id', 1)
? ?->inc('score')
? ?->update();
刪除數(shù)據(jù) ( delete ) :
# 根據(jù)主鍵刪除
Db::table('think_user')->delete(1);
Db::table('think_user')->delete([1, 2, 3]);
# 條件刪除
Db::table('think_user')->where('id', 1)->delete();
Db::table('think_user')->where('id', '<', 10)->delete();
2.4 ? ?thinkphp6 中間件與事件
2.4.1 ? ?中間件
可以通過(guò)命令行指令快速生成中間件
php think make:middleware Check
這個(gè)指令會(huì) ?app/middleware
目錄下面生成一個(gè) Check
中間件。
<?php
namespace app\middleware;
class Check
{
? ?public function handle($request, \Closure $next)
? ?{
if ($request->param('name') == 'nahida') {
? ?return redirect('/index/nahida');
}
#在這個(gè)中間件中我們判斷當(dāng)前請(qǐng)求的name參數(shù)等于nahida的時(shí)候進(jìn)行重定向處理。否則,請(qǐng)求將進(jìn)一步傳遞到應(yīng)用中。要讓請(qǐng)求繼續(xù)傳遞到應(yīng)用程序中,只需使用 $request 作為參數(shù)去調(diào)用回調(diào)函數(shù) $next 。
return $next($request);
? ?}
}
注意:中間件方法必須返回 Response 對(duì)象實(shí)例。
中間件主要用于攔截或過(guò)濾應(yīng)用的 HTTP
請(qǐng)求,并進(jìn)行必要的業(yè)務(wù)處理。
2.4.2 ? ?事件
tp6 的事件系統(tǒng)可以看作是 把 5.1 版本行為和鉤子以及模型事件、數(shù)據(jù)庫(kù)事件等的整合到一起的升級(jí)版。事件系統(tǒng)使用了觀察者模式,提供了較好的應(yīng)用解耦方式。
比如,我們要實(shí)現(xiàn)登錄成功后記錄一條日志的功能,就可以用事件來(lái)實(shí)現(xiàn)。原理是登錄成功后觸發(fā)日志寫入的事件。
控制器中登錄方法 :
...
? ? ?public function login()
? ?{
? ? ? ?// 假如登錄成功
? ? ? ?// TODO ?調(diào)用寫入日志的方法
? ?} ?
...
創(chuàng)建事件監(jiān)聽類 :
// 創(chuàng)建到 common 公共目錄下,方便其模塊使用。
php think make:listener common@UserLogin
UserLogin.php
<?php
declare (strict_types = 1);
namespace app\common\listener;
class UserlUserLoginogin
{
? ?/**
? ? * 事件監(jiān)聽處理
? ? *
? ? * @return mixed
? ? */
? ?public function handle($event)
? ?{
? ? ? ?//
? ?}
}
事件定義文件中定義對(duì)應(yīng)事件的監(jiān)聽。
event.php
<?php
// 事件定義文件
return [
? ?'bind' ? ? ?=> [
? ?],
? ?'listen' ? ?=> [
? ? ? ?'AppInit' ?=> [],
? ? ? ?'HttpRun' ?=> [],
? ? ? ?'HttpEnd' ?=> [],
? ? ? ?'LogLevel' => [],
? ? ? ?'LogWrite' => [],
? ? ? ?'UserLogin' ? ?=> ? ?['app\common\listener\UserLogin'],
? ?],
? ?'subscribe' => [
? ?],
];
UserLogin.php
...
? ?public function handle($event)
? ?{
? ? ? ?echo '這里是日志寫入邏輯';
? ? ? ?var_dump($event);
? ?}
...
在控制器可以觸發(fā)事件 :
...
use think\facade\Event;
...
? public function login()
? ?{
? ? ? ?// 假如登錄成功
? ? ? ?$userInfo = [
? ? ? ? ? ?'id' => 1,
? ? ? ? ? ?'name' => 'admin'
? ? ? ?];
? ? ? ?Event::trigger('UserLogin',$userInfo);
? ?}
...
運(yùn)行查看 :

事件相比較中間件的優(yōu)勢(shì)是事件比中間件更加精準(zhǔn)定位(或者說(shuō)粒度更細(xì)),并且更適合一些業(yè)務(wù)場(chǎng)景的擴(kuò)展。
2.5 ? ?think 命令
項(xiàng)目根目錄 cmd 命令行執(zhí)行 php think , 會(huì)出現(xiàn)下面提示信息
>php think
version 6.0.7
Usage:
?command [options] [arguments]
Options:
?-h, --help ? ?Display this help message
?-V, --version Display this console version
?-q, --quiet ? Do not output any message
? ? ?--ansi ? ?Force ANSI output
? ? ?--no-ansi Disable ANSI output
?-n, --no-interaction ?Do not ask any interactive question
?-v|vv|vvv, --verbose ?Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3
for debug
Available commands:
?build ? ? Build App Dirs
?clear ? ? Clear runtime file
?help ? ? ?Displays help for a command
?list ? ? ?Lists commands
?run ? ? ? PHP Built-in Server for ThinkPHP
?version ? show thinkphp framework version
make
?make:command ? ? ?Create a new command class
?make:controller ? Create a new resource controller class
?make:eventCreate a new event class
?make:listener ? ? Create a new listener class
?make:middleware ? Create a new middleware class
?make:modelCreate a new model class
?make:service ? ? ?Create a new Service class
?make:subscribe ? ?Create a new subscribe class
?make:validate ? ? Create a validate class
optimize
?optimize:route ? ?Build app route cache.
?optimize:schema ? Build database schema cache.
route
?route:listshow route list.
service
?service:discover ?Discover Services for ThinkPHP
vendor
?vendor:publish ? ?Publish any publishable assets from vendor packages
系統(tǒng)自帶的常用命令,包括 :

注意:更多的指令可以自己擴(kuò)展。