詳解PHP的Yii框架中的Controller控制器
控制器是 MVC 模式中的一部分, 是繼承yii\base\Controller類的對象,負(fù)責(zé)處理請求和生成響應(yīng)。 具體來說,控制器從應(yīng)用主體接管控制后會分析請求數(shù)據(jù)并傳送到模型, 傳送模型結(jié)果到視圖,最后生成輸出響應(yīng)信息。
操作
控制器由 操作 組成,它是執(zhí)行終端用戶請求的最基礎(chǔ)的單元,一個(gè)控制器可有一個(gè)或多個(gè)操作。
如下示例顯示包含兩個(gè)操作view and create 的控制器post:
namespace app\controllers; use Yii; use app\models\Post; use yii\web\Controller; use yii\web\NotFoundHttpException; class PostController extends Controller { public function actionView($id) { $model = Post::findOne($id); if ($model === null) { throw new NotFoundHttpException; } return $this->render('view', [ 'model' => $model, ]); } public function actionCreate() { $model = new Post; if ($model->load(Yii::$app->request->post()) && $model->save()) { return $this->redirect(['view', 'id' => $model->id]); } else { return $this->render('create', [ 'model' => $model, ]); } } }
在操作 view (定義為 actionView() 方法)中, 代碼首先根據(jù)請求模型ID加載 模型, 如果加載成功,會渲染名稱為view的視圖并顯示,否則會拋出一個(gè)異常。
在操作 create (定義為 actionCreate() 方法)中, 代碼相似. 先將請求數(shù)據(jù)填入模型, 然后保存模型,如果兩者都成功,會跳轉(zhuǎn)到ID為新創(chuàng)建的模型的view操作,否則顯示提供用戶輸入的create視圖。
路由
終端用戶通過所謂的路由尋找到操作,路由是包含以下部分的字符串:
- 模型ID: 僅存在于控制器屬于非應(yīng)用的模塊;
- 控制器ID: 同應(yīng)用(或同模塊如果為模塊下的控制器)下唯一標(biāo)識控制器的字符串;
- 操作ID: 同控制器下唯一標(biāo)識操作的字符串。
路由使用如下格式:
ControllerID/ActionID
如果屬于模塊下的控制器,使用如下格式:
ModuleID/ControllerID/ActionID
如果用戶的請求地址為 http://hostname/index.php?r=site/index, 會執(zhí)行site 控制器的index 操作。
創(chuàng)建控制器
在yii\web\Application網(wǎng)頁應(yīng)用中,控制器應(yīng)繼承yii\web\Controller 或它的子類。 同理在yii\console\Application控制臺應(yīng)用中,控制器繼承yii\console\Controller 或它的子類。 如下代碼定義一個(gè) site 控制器:
namespace app\controllers; use yii\web\Controller; class SiteController extends Controller { }
控制器ID
通常情況下,控制器用來處理請求有關(guān)的資源類型,因此控制器ID通常為和資源有關(guān)的名詞。 例如使用article作為處理文章的控制器ID。
控制器ID應(yīng)僅包含英文小寫字母、數(shù)字、下劃線、中橫杠和正斜杠, 例如 article 和 post-comment 是真是的控制器ID,article?, PostComment, admin\post不是控制器ID。
控制器Id可包含子目錄前綴,例如 admin/article 代表 yii\base\Application::controllerNamespace控制器命名空間下 admin子目錄中 article 控制器。 子目錄前綴可為英文大小寫字母、數(shù)字、下劃線、正斜杠,其中正斜杠用來區(qū)分多級子目錄(如panels/admin)。
控制器類命名
控制器ID遵循以下規(guī)則衍生控制器類名:
將用正斜杠區(qū)分的每個(gè)單詞第一個(gè)字母轉(zhuǎn)為大寫。注意如果控制器ID包含正斜杠,只將最后的正斜杠后的部分第一個(gè)字母轉(zhuǎn)為大寫;
去掉中橫杠,將正斜杠替換為反斜杠;
增加Controller后綴;
在前面增加yii\base\Application::controllerNamespace控制器命名空間.
下面為一些示例,假設(shè)yii\base\Application::controllerNamespace控制器命名空間為 app\controllers:
- article 對應(yīng) app\controllers\ArticleController;
- post-comment 對應(yīng) app\controllers\PostCommentController;
- admin/post-comment 對應(yīng) app\controllers\admin\PostCommentController;
- adminPanels/post-comment 對應(yīng) app\controllers\adminPanels\PostCommentController.
控制器類必須能被 自動(dòng)加載,所以在上面的例子中, 控制器article 類應(yīng)在 別名 為@app/controllers/ArticleController.php的文件中定義, 控制器admin/post2-comment應(yīng)在@app/controllers/admin/Post2CommentController.php文件中。
補(bǔ)充: 最后一個(gè)示例 admin/post2-comment 表示你可以將控制器放在 yii\base\Application::controllerNamespace控制器命名空間下的子目錄中, 在你不想用 模塊 的情況下給控制器分類,這種方式很有用。
控制器部署
可通過配置 yii\base\Application::controllerMap 來強(qiáng)制上述的控制器ID和類名對應(yīng), 通常用在使用第三方不能掌控類名的控制器上。
配置 應(yīng)用配置 中的application configuration,如下所示:
[ 'controllerMap' => [ // 用類名申明 "account" 控制器 'account' => 'app\controllers\UserController', // 用配置數(shù)組申明 "article" 控制器 'article' => [ 'class' => 'app\controllers\PostController', 'enableCsrfValidation' => false, ], ], ]
默認(rèn)控制器
每個(gè)應(yīng)用有一個(gè)由yii\base\Application::defaultRoute屬性指定的默認(rèn)控制器; 當(dāng)請求沒有指定 路由,該屬性值作為路由使用。 對于yii\web\Application網(wǎng)頁應(yīng)用,它的值為 'site', 對于 yii\console\Application控制臺應(yīng)用,它的值為 help, 所以URL為http://hostname/index.php 表示由 site 控制器來處理。
可以在 應(yīng)用配置 中修改默認(rèn)控制器,如下所示:
[ 'defaultRoute' => 'main', ]
創(chuàng)建操作
創(chuàng)建操作可簡單地在控制器類中定義所謂的 操作方法 來完成,操作方法必須是以action開頭的公有方法。 操作方法的返回值會作為響應(yīng)數(shù)據(jù)發(fā)送給終端用戶,如下代碼定義了兩個(gè)操作 index 和 hello-world:
namespace app\controllers; use yii\web\Controller; class SiteController extends Controller { public function actionIndex() { return $this->render('index'); } public function actionHelloWorld() { return 'Hello World'; } }
操作ID
操作通常是用來執(zhí)行資源的特定操作,因此,操作ID通常為動(dòng)詞,如view, update等。
操作ID應(yīng)僅包含英文小寫字母、數(shù)字、下劃線和中橫杠,操作ID中的中橫杠用來分隔單詞。 例如view, update2, comment-post是真實(shí)的操作ID,view?, Update不是操作ID.
可通過兩種方式創(chuàng)建操作ID,內(nèi)聯(lián)操作和獨(dú)立操作. An inline action is 內(nèi)聯(lián)操作在控制器類中定義為方法;獨(dú)立操作是繼承yii\base\Action或它的子類的類。 內(nèi)聯(lián)操作容易創(chuàng)建,在無需重用的情況下優(yōu)先使用; 獨(dú)立操作相反,主要用于多個(gè)控制器重用,或重構(gòu)為擴(kuò)展。
內(nèi)聯(lián)操作
內(nèi)聯(lián)操作指的是根據(jù)我們剛描述的操作方法。
操作方法的名字是根據(jù)操作ID遵循如下規(guī)則衍生:
- 將每個(gè)單詞的第一個(gè)字母轉(zhuǎn)為大寫;
- 去掉中橫杠;
- 增加action前綴.
- 例如index 轉(zhuǎn)成 actionIndex, hello-world 轉(zhuǎn)成 actionHelloWorld。
注意: 操作方法的名字大小寫敏感,如果方法名稱為ActionIndex不會認(rèn)為是操作方法, 所以請求index操作會返回一個(gè)異常,也要注意操作方法必須是公有的,私有或者受保護(hù)的方法不能定義成內(nèi)聯(lián)操作。
因?yàn)槿菀讋?chuàng)建,內(nèi)聯(lián)操作是最常用的操作,但是如果你計(jì)劃在不同地方重用相同的操作, 或者你想重新分配一個(gè)操作,需要考慮定義它為獨(dú)立操作。
獨(dú)立操作
獨(dú)立操作通過繼承yii\base\Action或它的子類來定義。 例如Yii發(fā)布的yii\web\ViewAction和yii\web\ErrorAction都是獨(dú)立操作。
要使用獨(dú)立操作,需要通過控制器中覆蓋yii\base\Controller::actions()方法在action map中申明,如下例所示:
public function actions() { return [ // 用類來申明"error" 操作 'error' => 'yii\web\ErrorAction', // 用配置數(shù)組申明 "view" 操作 'view' => [ 'class' => 'yii\web\ViewAction', 'viewPrefix' => '', ], ]; }
如上所示, actions() 方法返回鍵為操作ID、值為對應(yīng)操作類名或數(shù)組configurations 的數(shù)組。 和內(nèi)聯(lián)操作不同,獨(dú)立操作ID可包含任意字符,只要在actions() 方法中申明.
為創(chuàng)建一個(gè)獨(dú)立操作類,需要繼承yii\base\Action 或它的子類,并實(shí)現(xiàn)公有的名稱為run()的方法, run() 方法的角色和操作方法類似,例如:
<?php namespace app\components; use yii\base\Action; class HelloWorldAction extends Action { public function run() { return "Hello World"; } }
操作結(jié)果
操作方法或獨(dú)立操作的run()方法的返回值非常重要,它表示對應(yīng)操作結(jié)果。
返回值可為 響應(yīng) 對象,作為響應(yīng)發(fā)送給終端用戶。
對于yii\web\Application網(wǎng)頁應(yīng)用,返回值可為任意數(shù)據(jù), 它賦值給yii\web\Response::data, 最終轉(zhuǎn)換為字符串來展示響應(yīng)內(nèi)容。
對于yii\console\Application控制臺應(yīng)用,返回值可為整數(shù), 表示命令行下執(zhí)行的 yii\console\Response::exitStatus 退出狀態(tài)。
在上面的例子中,操作結(jié)果都為字符串,作為響應(yīng)數(shù)據(jù)發(fā)送給終端用戶,下例顯示一個(gè)操作通過 返回響應(yīng)對象(因?yàn)閥ii\web\Controller::redirect()方法返回一個(gè)響應(yīng)對象)可將用戶瀏覽器跳轉(zhuǎn)到新的URL。
public function actionForward()
{ // 用戶瀏覽器跳轉(zhuǎn)到 http://example.com return $this->redirect('http://example.com'); }
操作參數(shù)
內(nèi)聯(lián)操作的操作方法和獨(dú)立操作的 run() 方法可以帶參數(shù),稱為操作參數(shù)。 參數(shù)值從請求中獲取,對于yii\web\Application網(wǎng)頁應(yīng)用, 每個(gè)操作參數(shù)的值從$_GET中獲得,參數(shù)名作為鍵; 對于yii\console\Application控制臺應(yīng)用, 操作參數(shù)對應(yīng)命令行參數(shù)。
如下例,操作view (內(nèi)聯(lián)操作) 申明了兩個(gè)參數(shù) $id 和 $version。
namespace app\controllers; use yii\web\Controller; class PostController extends Controller { public function actionView($id, $version = null) { // ... } }
操作參數(shù)會被不同的參數(shù)填入,如下所示:
http://hostname/index.php?r=post/view&id=123: $id 會填入'123',$version 仍為 null 空因?yàn)闆]有version請求參數(shù);
http://hostname/index.php?r=post/view&id=123&version=2: $id 和 $version 分別填入 '123' 和 '2'`;
http://hostname/index.php?r=post/view: 會拋出yii\web\BadRequestHttpException 異常 因?yàn)檎埱鬀]有提供參數(shù)給必須賦值參數(shù)$id;
http://hostname/index.php?r=post/view&id[]=123: 會拋出yii\web\BadRequestHttpException 異常 因?yàn)?id 參數(shù)收到數(shù)字值 ['123']而不是字符串.
如果想讓操作參數(shù)接收數(shù)組值,需要指定$id為array,如下所示:
public function actionView(array $id, $version = null) { // ... }
現(xiàn)在如果請求為 http://hostname/index.php?r=post/view&id[]=123, 參數(shù) $id 會使用數(shù)組值['123'], 如果請求為http://hostname/index.php?r=post/view&id=123, 參數(shù) $id 會獲取相同數(shù)組值,因?yàn)闊o類型的'123'會自動(dòng)轉(zhuǎn)成數(shù)組。
上述例子主要描述網(wǎng)頁應(yīng)用的操作參數(shù),對于控制臺應(yīng)用,更多詳情請參閱控制臺命令。
默認(rèn)操作
每個(gè)控制器都有一個(gè)由 yii\base\Controller::defaultAction 屬性指定的默認(rèn)操作, 當(dāng)路由 只包含控制器ID,會使用所請求的控制器的默認(rèn)操作。
默認(rèn)操作默認(rèn)為 index,如果想修改默認(rèn)操作,只需簡單地在控制器類中覆蓋這個(gè)屬性,如下所示:
namespace app\controllers; use yii\web\Controller; class SiteController extends Controller { public $defaultAction = 'home'; public function actionHome() { return $this->render('home'); } }
控制器動(dòng)作參數(shù)綁定
從版本 1.1.4 開始,Yii 提供了對自動(dòng)動(dòng)作參數(shù)綁定的支持。就是說,控制器動(dòng)作可以定義命名的參數(shù),參數(shù)的值將由 Yii 自動(dòng)從 $_GET 填充。
為了詳細(xì)說明此功能,假設(shè)我們需要為 PostController 寫一個(gè) create 動(dòng)作。此動(dòng)作需要兩個(gè)參數(shù):
- category:一個(gè)整數(shù),代表帖子(post)要發(fā)表在的那個(gè)分類的ID。
- language:一個(gè)字符串,代表帖子所使用的語言代碼。
從 $_GET 中提取參數(shù)時(shí),我們可以不再下面這種無聊的代碼了:
class PostController extends CController { public function actionCreate() { if(isset($_GET['category'])) $category=(int)$_GET['category']; else throw new CHttpException(404,'invalid request'); if(isset($_GET['language'])) $language=$_GET['language']; else $language='en'; // ... fun code starts here ... } }
現(xiàn)在使用動(dòng)作參數(shù)功能,我們可以更輕松的完成任務(wù):
class PostController extends CController { public function actionCreate($category, $language='en') { $category = (int)$category; echo 'Category:'.$category.'/Language:'.$language; // ... fun code starts here ... } }
注意我們在動(dòng)作方法 actionCreate 中添加了兩個(gè)參數(shù)。這些參數(shù)的名字必須和我們想要從 $_GET 中提取的名字一致。當(dāng)用戶沒有在請求中指定 $language 參數(shù)時(shí),這個(gè)參數(shù)會使用默認(rèn)值 en 。由于 $category 沒有默認(rèn)值,如果用戶沒有在 $_GET 中提供 category 參數(shù),將會自動(dòng)拋出一個(gè) CHttpException (錯(cuò)誤代碼 400) 異常。
從版本1.1.5開始,Yii已經(jīng)支持?jǐn)?shù)組的動(dòng)作參數(shù)。使用方法如下:
class PostController extends CController { public function actionCreate(array $categories) { // Yii will make sure $categories be an array } }
控制器生命周期
處理一個(gè)請求時(shí),應(yīng)用主體 會根據(jù)請求路由創(chuàng)建一個(gè)控制器,控制器經(jīng)過以下生命周期來完成請求:
- 在控制器創(chuàng)建和配置后,yii\base\Controller::init() 方法會被調(diào)用。
- 控制器根據(jù)請求操作ID創(chuàng)建一個(gè)操作對象:
- 如果操作ID沒有指定,會使用yii\base\Controller::defaultAction默認(rèn)操作ID;
- 如果在yii\base\Controller::actions()找到操作ID,會創(chuàng)建一個(gè)獨(dú)立操作;
- 如果操作ID對應(yīng)操作方法,會創(chuàng)建一個(gè)內(nèi)聯(lián)操作;
- 否則會拋出yii\base\InvalidRouteException異常。
- 控制器按順序調(diào)用應(yīng)用主體、模塊(如果控制器屬于模塊)、控制器的 beforeAction() 方法;
- 如果任意一個(gè)調(diào)用返回false,后面未調(diào)用的beforeAction()會跳過并且操作執(zhí)行會被取消; action execution will be cancelled.
- 默認(rèn)情況下每個(gè) beforeAction() 方法會觸發(fā)一個(gè) beforeAction 事件,在事件中你可以追加事件處理操作;
- 控制器執(zhí)行操作:
- 請求數(shù)據(jù)解析和填入到操作參數(shù);
- 控制器按順序調(diào)用控制器、模塊(如果控制器屬于模塊)、應(yīng)用主體的 afterAction() 方法;
- 默認(rèn)情況下每個(gè) afterAction() 方法會觸發(fā)一個(gè) afterAction 事件,在事件中你可以追加事件處理操作;
- 應(yīng)用主體獲取操作結(jié)果并賦值給響應(yīng).
最佳實(shí)踐
在設(shè)計(jì)良好的應(yīng)用中,控制器很精練,包含的操作代碼簡短; 如果你的控制器很復(fù)雜,通常意味著需要重構(gòu),轉(zhuǎn)移一些代碼到其他類中。
歸納起來,控制器:
- 可訪問請求 數(shù)據(jù);
- 可根據(jù)請求數(shù)據(jù)調(diào)用 模型 的方法和其他服務(wù)組件;
- 可使用視圖構(gòu)造響應(yīng);
- 不應(yīng)處理應(yīng)被模型處理的請求數(shù)據(jù);
- 應(yīng)避免嵌入HTML或其他展示代碼,這些代碼最好在 視圖中處理.
- Yii2創(chuàng)建控制器(createController)方法詳解
- yii2控制器Controller Ajax操作示例
- Yii2使用$this->context獲取當(dāng)前的Module、Controller(控制器)、Action等
- Yii2設(shè)置默認(rèn)控制器的兩種方法
- Yii控制器中操作視圖js的方法
- Yii控制器中filter過濾器用法分析
- Yii2使用駝峰命名的形式訪問控制器(實(shí)例講解)
- Yii2框架控制器、路由、Url生成操作示例
- Yii2使用駝峰命名的形式訪問控制器的示例代碼
- yii2 在控制器中驗(yàn)證請求參數(shù)的使用方法
- Yii 框架控制器創(chuàng)建使用及控制器響應(yīng)操作示例
相關(guān)文章
學(xué)習(xí)php設(shè)計(jì)模式 php實(shí)現(xiàn)門面模式(Facade)
這篇文章主要介紹了php設(shè)計(jì)模式中的門面模式,使用php實(shí)現(xiàn)門面模式,感興趣的小伙伴們可以參考一下2015-12-12PHP 將圖片按創(chuàng)建時(shí)間進(jìn)行分類存儲的實(shí)現(xiàn)代碼
代碼功能:使用PHP巧妙將圖片按創(chuàng)建時(shí)間進(jìn)行分類存儲 圖片文件屬性須取消只讀屬性,否則無法刪除2010-01-01解析php session_set_save_handler 函數(shù)的用法(mysql)
本篇文章是對php中session_set_save_handler 函數(shù)的用法(mysql)進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06