首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

Yii 框架原始碼分析(三):請求處理與控制器執行流程

     編輯:PHP 相關知識

Yii 框架原始碼分析(三):請求處理與控制器執行流程

轉載請註明:TheViper https://www.cnblogs.com/TheViper/

上一篇分析了 CWebApplication 中透過 getUrlManager()->parseUrl() 解析路由得到 $route = controller/action。本篇將深入探討後續的 runController($route) 執行流程。

CWebApplication::runController()

<?php
class CWebApplication extends CApplication {
    // ... 屬性定義 ...
    
    public function processRequest() {
        $route = $this->getUrlManager()->parseUrl($this->getRequest());
        $this->runController($route);
    }
    
    public function runController($route) {
        if (($ca = $this->createController($route)) !== null) {
            list($controller, $actionID) = $ca;
            $oldController = $this->_controller;
            $this->_controller = $controller;
            $controller->init(); // 鉤子方法,子類別覆寫
            $controller->run($actionID); // 進入控制器執行 action
            $this->_controller = $oldController;
        }
    }
    
    public function createController($route, $owner = null) {
        // 解析 route 字串,建立控制器實例
        // 回傳 [controller實例, actionID]
    }
    // ... 其他方法 ...
}
?>

控制器建立與初始化

createController() 會從路由字串解析出控制器 ID 與動作 ID,載入對應的控制器類別檔案並實例化。控制器初始化時會呼叫 init() 鉤子,開發者可在子類別中覆寫,例如初始化資料庫連線:

<?php
class VideoController extends CController {
    public function init() {
        $this->db = Yii::app()->db;
    }
    public function actionBroadcast() {
        $b = $this->db->query("", array(1));
        $this->render("u_broadcast", array('b' => $b[0]));
    }
}
?>

CController::run() 與動作執行

<?php
class CController {
    public function run($actionID) {
        if (($action = $this->createAction($actionID)) !== null) {
            $parent = Yii::app();
            if ($parent->beforeControllerAction($this, $action)) {
                $this->runActionWithFilters($action, $this->filters());
                $parent->afterControllerAction($this, $action);
            }
        }
    }
    
    public function runActionWithFilters($action, $filters) {
        if (empty($filters))
            $this->runAction($action);
        else {
            $priorAction = $this->_action;
            $this->_action = $action;
            CFilterChain::create($this, $action, $filters)->run();
            $this->_action = $priorAction;
        }
    }
    
    public function runAction($action) {
        $priorAction = $this->_action;
        $this->_action = $action;
        if ($this->beforeAction($action)) {
            if ($action->runWithParams($this->getActionParams()) === false)
                $this->invalidActionParams($action);
            else
                $this->afterAction($action);
        }
        $this->_action = $priorAction;
    }
    // ... render, forward, createAction 等方法 ...
}
?>

內嵌動作與反射機制

Yii 使用 CInlineAction 封裝控制器中的動作方法,透過 PHP 反射 (ReflectionMethod) 動態呼叫:

<?php
class CInlineAction extends CAction {
    public function runWithParams($params) {
        $methodName = 'action' . $this->getId();
        $controller = $this->getController();
        $method = new ReflectionMethod($controller, $methodName);
        if ($method->getNumberOfParameters() > 0)
            return $this->runWithParamsInternal($controller, $method, $params);
        else
            return $controller->$methodName();
    }
}
?>

過濾器鏈機制

當控制器定義 filters() 時,Yii 會建立 CFilterChain 依序執行過濾器。過濾器支援針對特定動作啟用(如 'application.filters.LoginFilter+upload_video')。

<?php
class CFilterChain extends CList {
    public function run() {
        if ($this->offsetExists($this->filterIndex)) {
            $filter = $this->itemAt($this->filterIndex++);
            $filter->filter($this); // 執行前置/後置過濾
        } else {
            $this->controller->runAction($this->action); // 所有過濾器完成,執行實際動作
        }
    }
    
    public static function create($controller, $action, $filters) {
        // 解析過濾器設定,建立 CInlineFilter 或 CFilter 實例
    }
}
?>

自訂過濾器範例

<?php
class LoginFilter extends CFilter {
    protected function preFilter($filterChain) {
        if (!isset($_SESSION)) session_start();
        if (isset($_SESSION['user'])) return true;
        else {
            setcookie("return", Yii::app()->getRequest()->getUrl(), time()+360, '/');
            Yii::app()->getRequest()->redirect('https://localhost/youtube/login', true, 302);
            return false;
        }
    }
    protected function postFilter($filterChain) {}
}
?>

總結

Yii 的請求處理流程:UrlManager 解析路由 → 建立控制器 → 初始化 → 執行動作(含過濾器鏈)→ 渲染視圖。過濾器鏈透過遞迴方式依序執行,最後回歸 runAction() 執行實際業務邏輯。forward() 方法可實現內部轉向,本質上是再次呼叫 runController()。

附上裁剪版 Yii 框架:framework.zip

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved