国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

YII2源碼分析(1) --- 基本流程分析

ghnor / 1341人閱讀

摘要:在分析源碼的過程中主要借助了工具。運(yùn)行應(yīng)用分析在上面的構(gòu)造函數(shù)執(zhí)行完后,開始運(yùn)行應(yīng)用。發(fā)送響應(yīng)到終端用戶入口腳本接收應(yīng)用主體傳來(lái)的退出狀態(tài)并完成請(qǐng)求的處理。

前言

本文主要分析Yii2應(yīng)用的啟動(dòng)、運(yùn)行的過程,主要包括以下三部分:入口腳本、啟動(dòng)應(yīng)用、運(yùn)行應(yīng)用。
在分析源碼的過程中主要借助了Xdebug工具。


入口腳本

文件位置:webindex.php

//定義全局變量
defined("YII_DEBUG") or define("YII_DEBUG", true);
defined("YII_ENV") or define("YII_ENV", "dev");

//composer自動(dòng)加載代碼機(jī)制,可參考 https://segmentfault.com/a/1190000010788354
require(__DIR__ . "/../vendor/autoload.php");

//1.引入工具類Yii
//2.注冊(cè)自動(dòng)加載函數(shù)
//3.生成依賴注入中使用到的容器
require(__DIR__ . "/../vendor/yiisoft/yii2/Yii.php");

//加載應(yīng)用配置
$config = require(__DIR__ . "/../config/web.php");

//生成應(yīng)用并運(yùn)行
(new yiiwebApplication($config))->run();

分析: (new yiiwebApplication($config))->run()

根據(jù)$config配置,生成應(yīng)用實(shí)例(啟動(dòng)應(yīng)用:new yiiwebApplication($config))

運(yùn)行應(yīng)用實(shí)例(運(yùn)行應(yīng)用:yiiwebApplication::run())


啟動(dòng)應(yīng)用:new yiiwebApplication($config)

分析:new yiiwebApplication($config)
主要就是執(zhí)行構(gòu)造函數(shù)(代碼位置:vendoryiisoftyii2aseApplication.php)

public function __construct($config = [])
{
  //將Yii::$app指向當(dāng)前的Application實(shí)例,因此后續(xù)就可以通過Yii::$app來(lái)調(diào)用應(yīng)用
  Yii::$app = $this;

  //調(diào)用yiiaseModule::setInstance($instance)
  //將Application實(shí)例本身記錄為“已加載模塊”  
  //詳細(xì)參考本文后續(xù)“1-1分析”
  static::setInstance($this);

  //設(shè)置當(dāng)前應(yīng)用狀態(tài)
  $this->state = self::STATE_BEGIN;

  //進(jìn)行一些預(yù)處理(根據(jù)$config配置應(yīng)用)
  //詳細(xì)代碼位置:yiiaseApplication::preInit(&$config)
  //主要根據(jù)config文件做了以下這些事情
  //1.判斷$config中是否有配置項(xiàng)‘id’(必須有,否則拋異常)
  //2.設(shè)置別名:@app,@vendor,@bower,@npm,@runtime
  //3.設(shè)置時(shí)間區(qū)域(timeZone)
  //4.自定義配置容器(Yii::$container)的屬性(由這里我們知道可以自定義配置容器)
  //5.合并核心組件配置到自定義組件配置:數(shù)組$config["components"]
  //(核心組件有哪些參考:yiiwebApplication::coreComponents())
  //(注意:這個(gè)方法中$config使用了引用,所以合并$config["components"]可以改變$config原來(lái)的值)
  $this->preInit($config);

  //注冊(cè)ErrorHandler,這樣一旦拋出了異常或錯(cuò)誤,就會(huì)由其負(fù)責(zé)處理
  //代碼位置:yiiaseApplication::registerErrorHandler(&$config) 
  //詳細(xì)參考本文后續(xù)“1-2分析”
  $this->registerErrorHandler($config);

  //根據(jù)$config配置Application
  //然后執(zhí)行yiiwebApplication::init()(實(shí)際上是執(zhí)行yiiaseApplication::init())
  //詳細(xì)參考本文后續(xù)“1-3分析”
  Component::__construct($config);
}

1-1分析:yiiaseModule::setInstance($instance)

public static function setInstance($instance)
{
    if ($instance === null) {
        unset(Yii::$app->loadedModules[get_called_class()]);
    } else {
        //將Application實(shí)例本身記錄為“已加載模塊”
        Yii::$app->loadedModules[get_class($instance)] = $instance;
    }
}

1-2分析:yiiaseApplication::registerErrorHandler(&$config)

//yiiwebApplication的 $errorHandler 對(duì)應(yīng) yiiwebErrorHandler(由yiiwebApplication::coreComponents()得知)
//而yiiwebErrorHandler繼承自yiiaseErrorHandler
protected function registerErrorHandler(&$config)
{
    if (YII_ENABLE_ERROR_HANDLER) {
        if (!isset($config["components"]["errorHandler"]["class"])) {
            echo "Error: no errorHandler component is configured.
";
            exit(1);
        }
        //可以看到就是根據(jù)$config["components"]["errorHandler"]來(lái)配置
        $this->set("errorHandler", $config["components"]["errorHandler"]);
        unset($config["components"]["errorHandler"]);
        //通過PHP函數(shù)注冊(cè)error handler(具體參考下面的yiiaseErrorHandler::register())
        $this->getErrorHandler()->register();
    }
}



//默認(rèn)config文件關(guān)于error handler的配置,這里的配置會(huì)合并到Y(jié)ii2本身對(duì)核心組件的定義中去(),核心組件的定義在yiiwebApplication::coreComponents()
"components" => [
        "errorHandler" => [
            "errorAction" => "site/error",
        ],
],



//yiiaseErrorHandler::register()
public function register()
{   
    //該選項(xiàng)設(shè)置是否將錯(cuò)誤信息作為輸出的一部分顯示到屏幕,
    //或者對(duì)用戶隱藏而不顯示。
        ini_set("display_errors", false);
 
    //當(dāng)拋出異常且沒有被catch的時(shí)候,由yiiaseErrorHandler::handleException()處理
    set_exception_handler([$this, "handleException"]);
    if (defined("HHVM_VERSION")) {
        set_error_handler([$this, "handleHhvmError"]);
    } else {
        //當(dāng)出現(xiàn)error的時(shí)候由yiiaseErrorHandler::handleError()處理
        set_error_handler([$this, "handleError"]);
    }
    if ($this->memoryReserveSize > 0) {
        $this->_memoryReserve = str_repeat("x", $this->memoryReserveSize);
    }
    ////當(dāng)出現(xiàn)fatal error的時(shí)候由yiiaseErrorHandler::handleFatalError()處理
    register_shutdown_function([$this, "handleFatalError"]);
}

一個(gè)值得注意的地方:
在handleException()、handleError()、handleFatalError()中會(huì)直接或間接調(diào)用yiiwebErrorHandle::renderException(),而在這個(gè)函數(shù)里面,有以下這一行代碼
$result = Yii::$app->runAction($this->errorAction);
回顧上面config文件中對(duì)errorAction這個(gè)屬性的定義,我們知道可以通過自定義一個(gè)action用于在異常或錯(cuò)誤時(shí)顯示自定義的出錯(cuò)頁(yè)面
例如yii2中默認(rèn)使用’site/error’這個(gè)action來(lái)處理

1-3分析:Component::__construct($config)
(代碼實(shí)際位置:vendoryiisoftyii2aseObject.php)

public function __construct($config = [])
{
    if (!empty($config)) {
        //見下面的詳細(xì)分析
        Yii::configure($this, $config);
    }
    //跳轉(zhuǎn)到y(tǒng)iiaseApplication::init(),見下面的分析
    $this->init();
}


//Yii::configure($object, $properties)分析
//實(shí)際上就是為Application的屬性賦值
//注意:這里會(huì)觸發(fā)一些魔術(shù)方法,間接調(diào)用了:
//yiiwebApplication::setHomeUrl()
//yiidiServiceLocator::setComponents()(這個(gè)值得注意,詳細(xì)參考本文后續(xù)“1-3-1分析”)
//yiiaseModule::setModules()
public static function configure($object, $properties)
{
    foreach ($properties as $name => $value) {
        $object->$name = $value;
    }

    return $object;
}


yiiaseApplication::init()分析
public function init()
{
    //設(shè)置當(dāng)前應(yīng)用狀態(tài)
    $this->state = self::STATE_INIT;
    //見下面的bootstrap()
    $this->bootstrap();
}

protected function bootstrap()
{
    //request是核心組件,這里使用了依賴注入機(jī)制(ServiceLocator)來(lái)獲取request
    //注意:這里是第一次調(diào)用request組件,會(huì)初始化該組件
    $request = $this->getRequest();
    //設(shè)置別名
    Yii::setAlias("@webroot", dirname($request->getScriptFile()));
    Yii::setAlias("@web", $request->getBaseUrl());
     
    //跳轉(zhuǎn)到y(tǒng)iiaseApplication::bootstrap(),詳細(xì)參考本文后續(xù)“1-3-2分析”
    //在這里主要是處理第三方擴(kuò)展(extensions)和一些預(yù)啟動(dòng)(bootstrap)
    parent::bootstrap();
}

1-3-1分析:yiidiServiceLocator::setComponents()

public function setComponents($components)
{
    foreach ($components as $id => $component) {
        //設(shè)置各個(gè)組件的定義,這樣后續(xù)就能通過依賴注入機(jī)制來(lái)獲取獲取組件了
        //應(yīng)該還記得這里的配置參數(shù)來(lái)源于config文件中的定義和yiiwebApplication::coreComponents()中的定義
        $this->set($id, $component);
    }
}

1-3-2分析:yiiaseApplication::bootstrap()

protected function bootstrap()
{
    if ($this->extensions === null) {
        //@vendor/yiisoft/extensions.php是一些關(guān)于第三方擴(kuò)展的配置,當(dāng)用composer require安裝第三擴(kuò)展的時(shí)候就會(huì)將新的擴(kuò)展的相關(guān)信息記錄到該文件,這樣我們就可以在代碼中調(diào)用了
        $file = Yii::getAlias("@vendor/yiisoft/extensions.php");
        $this->extensions = is_file($file) ? include($file) : [];
    }
    foreach ($this->extensions as $extension) {
        if (!empty($extension["alias"])) {
            foreach ($extension["alias"] as $name => $path) {
                Yii::setAlias($name, $path);
            }
        }
        //進(jìn)行一些必要的預(yù)啟動(dòng)
        if (isset($extension["bootstrap"])) {
            $component = Yii::createObject($extension["bootstrap"]);
            if ($component instanceof BootstrapInterface) {
                Yii::trace("Bootstrap with " . get_class($component) . "::bootstrap()", __METHOD__);
                $component->bootstrap($this);
            } else {
                Yii::trace("Bootstrap with " . get_class($component), __METHOD__);
            }
        }
    }
    
    //預(yù)啟動(dòng),通常會(huì)包括‘log’組件,‘debug’模塊和‘gii’模塊(參考配置文件)
    foreach ($this->bootstrap as $class) {
        $component = null;
        if (is_string($class)) {
            if ($this->has($class)) {
                $component = $this->get($class);
            } elseif ($this->hasModule($class)) {
                $component = $this->getModule($class);
            } elseif (strpos($class, "") === false) {
                throw new InvalidConfigException("Unknown bootstrapping component ID: $class");
            }
        }
        if (!isset($component)) {
            $component = Yii::createObject($class);
        }

        if ($component instanceof BootstrapInterface) {
            Yii::trace("Bootstrap with " . get_class($component) . "::bootstrap()", __METHOD__);
            $component->bootstrap($this);
        } else {
            Yii::trace("Bootstrap with " . get_class($component), __METHOD__);
        }
    }
}

在完成了上面的流程之后,應(yīng)用就算啟動(dòng)成功了,可以開始運(yùn)行,處理請(qǐng)求了。


運(yùn)行應(yīng)用:yiiwebApplication::run()

分析:yiiaseApplication::run()
在上面的構(gòu)造函數(shù)執(zhí)行完后,開始運(yùn)行應(yīng)用。即下面這行代碼的run()部分
(new yiiwebApplication($config))->run();//(實(shí)際上執(zhí)行的是yiiaseApplication::run())

public function run()
{
    try {

        $this->state = self::STATE_BEFORE_REQUEST;
        //觸發(fā)事件’beforeRequest’,依次執(zhí)行該事件的handler,
        $this->trigger(self::EVENT_BEFORE_REQUEST);

        $this->state = self::STATE_HANDLING_REQUEST;
        //處理請(qǐng)求,這里的返回值是yiiwebResponse實(shí)例
        //handleRequest(),詳細(xì)參考本文后續(xù)“2-1分析”
        $response = $this->handleRequest($this->getRequest());

        $this->state = self::STATE_AFTER_REQUEST;
        //觸發(fā)事件’afterRequest’,依次執(zhí)行該事件的handler
        $this->trigger(self::EVENT_AFTER_REQUEST);

        $this->state = self::STATE_SENDING_RESPONSE;
        //發(fā)送響應(yīng),詳細(xì)參考本文后續(xù)“2-2分析”
        $response->send();

        $this->state = self::STATE_END;

        return $response->exitStatus;

    } catch (ExitException $e) {
        //結(jié)束運(yùn)行
        $this->end($e->statusCode, isset($response) ? $response : null);
        return $e->statusCode;

    }
}

2-1分析: yiiwebApplication::handleRequest()

public function handleRequest($request)
{
    if (empty($this->catchAll)) {
        try {
            //解析請(qǐng)求得到路由和相應(yīng)的參數(shù),這里會(huì)調(diào)用urlManager組件來(lái)處理
            list ($route, $params) = $request->resolve();
        } catch (UrlNormalizerRedirectException $e) {
            $url = $e->url;
            if (is_array($url)) {
                if (isset($url[0])) {
                    // ensure the route is absolute
                    $url[0] = "/" . ltrim($url[0], "/");
                }
                $url += $request->getQueryParams();
            }
            //當(dāng)解析請(qǐng)求出現(xiàn)異常時(shí)進(jìn)行重定向
            return $this->getResponse()->redirect(Url::to($url, $e->scheme), $e->statusCode);
        }
    } else {
        //’catchAll’參數(shù)可以在配置文件中自定義,可用于在項(xiàng)目需要臨時(shí)下線維護(hù)時(shí)給出一個(gè)統(tǒng)一的訪問路由
        $route = $this->catchAll[0];
        $params = $this->catchAll;
        unset($params[0]);
    }
    try {
        Yii::trace("Route requested: "$route"", __METHOD__);
        //記錄下當(dāng)前請(qǐng)求的route
        $this->requestedRoute = $route;
        //執(zhí)行路由相對(duì)應(yīng)的action(yiiaseModule::runAction()詳細(xì)參考本文后續(xù)“2-1-1分析”)
        $result = $this->runAction($route, $params);
        if ($result instanceof Response) {
            return $result;
        } else {
            //如果action的返回結(jié)果不是Response的實(shí)例,則將結(jié)果封裝到Response實(shí)例的data屬性中
            $response = $this->getResponse();
            if ($result !== null) {
                $response->data = $result;
            }

            return $response;
        }
    } catch (InvalidRouteException $e) {
        throw new NotFoundHttpException(Yii::t("yii", "Page not found."), $e->getCode(), $e);
    }
}

2-1-1分析: yiiaseModule::runAction()

public function runAction($route, $params = [])
{
    //根據(jù)路由創(chuàng)建Controller實(shí)例(詳細(xì)參考本文后續(xù)“2-1-1-1分析”)
    $parts = $this->createController($route);
    if (is_array($parts)) {
        /* @var $controller Controller */
        list($controller, $actionID) = $parts;
        $oldController = Yii::$app->controller;
        //設(shè)置當(dāng)前的Controller實(shí)例
        Yii::$app->controller = $controller;
        //執(zhí)行action(yiiaseController::runAction()詳細(xì)參考本文后續(xù)“2-1-1-2分析”)
        $result = $controller->runAction($actionID, $params);
        if ($oldController !== null) {
            //可以看做是棧
            Yii::$app->controller = $oldController;
        }

        return $result;
    }

    $id = $this->getUniqueId();
    throw new InvalidRouteException("Unable to resolve the request "" . ($id === "" ? $route : $id . "/" . $route) . "".");
}

2-1-1-1分析: yiiaseModule::createController()

public function createController($route)
{
    //如果route為空則設(shè)置route為默認(rèn)路由,這個(gè)可以在配置文件中自定義
    if ($route === "") {
        $route = $this->defaultRoute;
    }

    // double slashes or leading/ending slashes may cause substr problem
    $route = trim($route, "/");
    if (strpos($route, "http://") !== false) {
        return false;
    }

    if (strpos($route, "/") !== false) {
        list ($id, $route) = explode("/", $route, 2);
    } else {
        $id = $route;
        $route = "";
    }

    //優(yōu)先使用controllerMap,controllerMap可以如下
    /*
     [
         "account" => "appcontrollersUserController",
         "article" => [
             "class" => "appcontrollersPostController",
             "pageTitle" => "something new",
         ],
      ]
    */
    // module and controller map take precedence
    if (isset($this->controllerMap[$id])) {
        $controller = Yii::createObject($this->controllerMap[$id], [$id, $this]);
        return [$controller, $route];
    }
    
    //先判斷是否存在相應(yīng)的模塊
    $module = $this->getModule($id);
    if ($module !== null) {
        //當(dāng)存在模塊時(shí),進(jìn)行遞歸
        return $module->createController($route);
    }
    
    if (($pos = strrpos($route, "/")) !== false) {
        $id .= "/" . substr($route, 0, $pos);
        $route = substr($route, $pos + 1);
    }
    
    //最終找到Controller的id
    $controller = $this->createControllerByID($id);
    if ($controller === null && $route !== "") {
        //詳細(xì)見下面的代碼分析
        $controller = $this->createControllerByID($id . "/" . $route);
        $route = "";
    }
    //返回Controller實(shí)例和剩下的路由信息
    return $controller === null ? false : [$controller, $route];
}


    
public function createControllerByID($id)
{
    $pos = strrpos($id, "/");
    if ($pos === false) {
        $prefix = "";
        $className = $id;
    } else {
        $prefix = substr($id, 0, $pos + 1);
        $className = substr($id, $pos + 1);
    }

    if (!preg_match("%^[a-z][a-z0-9-_]*$%", $className)) {
        return null;
    }
    if ($prefix !== "" && !preg_match("%^[a-z0-9_/]+$%i", $prefix)) {
        return null;
    }
    //進(jìn)行一些轉(zhuǎn)換
    $className = str_replace(" ", "", ucwords(str_replace("-", " ", $className))) . "Controller";
    $className = ltrim($this->controllerNamespace . "" . str_replace("/", "", $prefix)  . $className, "");
    if (strpos($className, "-") !== false || !class_exists($className)) {
        return null;
    }

    if (is_subclass_of($className, "yiiaseController")) {
        //通過依賴注入容器獲得Controller實(shí)例
        $controller = Yii::createObject($className, [$id, $this]);
        return get_class($controller) === $className ? $controller : null;
    } elseif (YII_DEBUG) {
        throw new InvalidConfigException("Controller class must extend from yiiaseController.");
    }
    return null;
}

2-1-1-2分析:yiiaseController::runAction()

public function runAction($id, $params = [])
{
    //創(chuàng)建action實(shí)例,詳細(xì)見下面的代碼
    $action = $this->createAction($id);
    if ($action === null) {
        throw new InvalidRouteException("Unable to resolve the request: " . $this->getUniqueId() . "/" . $id);
    }

    Yii::trace("Route to run: " . $action->getUniqueId(), __METHOD__);

    if (Yii::$app->requestedAction === null) {
        Yii::$app->requestedAction = $action;
    }

    $oldAction = $this->action;
    $this->action = $action;

    $modules = [];
    $runAction = true;

    //返回的modules包括該controller當(dāng)前所在的module,以及該module的所有祖先module(遞歸直至沒有祖先module)
    //然后從最初的祖先module開始,依次執(zhí)行“模塊級(jí)”的beforeActio()
    //如果有beforeAction()沒有返回true, 那么會(huì)中斷后續(xù)的執(zhí)行
    // call beforeAction on modules
    foreach ($this->getModules() as $module) {
        if ($module->beforeAction($action)) {
            array_unshift($modules, $module);
        } else {
            $runAction = false;
            break;
        }
    }

    $result = null;

    //執(zhí)行當(dāng)前控制器的beforeAction,通過后再最終執(zhí)行action
    //(如果前面“模塊級(jí)beforeAction”沒有全部返回true,則這里不會(huì)執(zhí)行)
    if ($runAction && $this->beforeAction($action)) {
        // run the action
        //(代碼位置:yiiaseInlineAction::runWithParams()詳細(xì)參考本文后續(xù)“2-1-1-2-1分析”和yiiaseAction::runWithParams()詳細(xì)參考本文后續(xù)“2-1-1-2-2分析”)
        $result = $action->runWithParams($params);


        //執(zhí)行當(dāng)前Controller的afterAction
        $result = $this->afterAction($action, $result);

        //從當(dāng)前模塊開始,執(zhí)行afterAction,直至所有祖先的afterAction
        // call afterAction on modules
        foreach ($modules as $module) {
            /* @var $module Module */
            $result = $module->afterAction($action, $result);
        }
    }

    if ($oldAction !== null) {
        $this->action = $oldAction;
    }

    //如果有beforeAction沒有通過,那么會(huì)返回null
    return $result;
}


public function createAction($id)
{
    //默認(rèn)action
    if ($id === "") {
        $id = $this->defaultAction;
    }

    //獨(dú)立action(Standalone Actions )
    $actionMap = $this->actions();
    if (isset($actionMap[$id])) {
        //返回一個(gè)action實(shí)例,通常是yiiaseAction的子類
        return Yii::createObject($actionMap[$id], [$id, $this]);
    } elseif (preg_match("/^[a-z0-9-_]+$/", $id) && strpos($id, "--") === false && trim($id, "-") === $id) {
        $methodName = "action" . str_replace(" ", "", ucwords(implode(" ", explode("-", $id))));
        if (method_exists($this, $methodName)) {
            $method = new ReflectionMethod($this, $methodName);
            if ($method->isPublic() && $method->getName() === $methodName) {
                //InlineAction封裝了將要執(zhí)行的action的相關(guān)信息,該類繼承自yiiaseAction
                return new InlineAction($id, $this, $methodName);
            }
        }
    }

    return null;
}

2-1-1-2-1分析: yiiaseInlineAction::runWithParams()

public function runWithParams($params)
{
    //yiiwebController::bindActionParams()詳細(xì)參考本文后續(xù)“2-1-1-2-1-1分析”
    $args = $this->controller->bindActionParams($this, $params);
    Yii::trace("Running action: " . get_class($this->controller) . "::" . $this->actionMethod . "()", __METHOD__);
    if (Yii::$app->requestedParams === null) {
        Yii::$app->requestedParams = $args;
    }
    
    //真正地調(diào)用開發(fā)者寫的Action代碼
    return call_user_func_array([$this->controller, $this->actionMethod], $args);
}

2-1-1-2-2分析:yiiaseAction::runWithParams()

public function runWithParams($params)
{
    if (!method_exists($this, "run")) {
        throw new InvalidConfigException(get_class($this) . " must define a "run()" method.");
    }
    //yiiwebController::bindActionParams()詳細(xì)參考本文后續(xù)“2-1-1-2-1-1分析”
    $args = $this->controller->bindActionParams($this, $params);
    Yii::trace("Running action: " . get_class($this) . "::run()", __METHOD__);
    if (Yii::$app->requestedParams === null) {
        Yii::$app->requestedParams = $args;
    }
    if ($this->beforeRun()) {
        //執(zhí)行獨(dú)立Action的run方法
        $result = call_user_func_array([$this, "run"], $args);
        $this->afterRun();

        return $result;
    } else {
        return null;
    }
}

2-1-1-2-1-1分析:yiiwebController::bindActionParams()

public function bindActionParams($action, $params)
{
    if ($action instanceof InlineAction) {
        //如果是InlineAction則對(duì)Controller中相應(yīng)的action方法進(jìn)行反射
        $method = new ReflectionMethod($this, $action->actionMethod);
    } else {
        //如果是獨(dú)立action則對(duì)該Action類的run方法進(jìn)行反射
        $method = new ReflectionMethod($action, "run");
    }

    $args = [];
    $missing = [];
    $actionParams = [];
    //通過php提供的反射機(jī)制綁定Action的參數(shù),同時(shí)還會(huì)判斷url中的參數(shù)是否滿足要求
    foreach ($method->getParameters() as $param) {
        $name = $param->getName();
        if (array_key_exists($name, $params)) {
            if ($param->isArray()) {
                $args[] = $actionParams[$name] = (array) $params[$name];
            } elseif (!is_array($params[$name])) {
                $args[] = $actionParams[$name] = $params[$name];
            } else {
                throw new BadRequestHttpException(Yii::t("yii", "Invalid data received for parameter "{param}".", [
                    "param" => $name,
                ]));
            }
            unset($params[$name]);
        } elseif ($param->isDefaultValueAvailable()) {
            $args[] = $actionParams[$name] = $param->getDefaultValue();
        } else {
            $missing[] = $name;
        }
    }

    if (!empty($missing)) {
        throw new BadRequestHttpException(Yii::t("yii", "Missing required parameters: {params}", [
            "params" => implode(", ", $missing),
        ]));
    }

    $this->actionParams = $actionParams;

    return $args;
}

2-2分析: yiiwebResponse::send()

public function send()
{
    if ($this->isSent) {
        return;
    }
    $this->trigger(self::EVENT_BEFORE_SEND);
    //預(yù)處理,詳見下面的代碼
    $this->prepare();
    $this->trigger(self::EVENT_AFTER_PREPARE);
    //發(fā)送http響應(yīng)的頭部,詳見下面的代碼
    $this->sendHeaders();
    //發(fā)送http響應(yīng)的主體,詳見下面的代碼
    $this->sendContent();
    $this->trigger(self::EVENT_AFTER_SEND);
    $this->isSent = true;
}


protected function prepare()
{
    if ($this->stream !== null) {
        return;
    }
    
    //使用formatter對(duì)相應(yīng)進(jìn)行處理,這個(gè)可以在配置文件中自定義
    if (isset($this->formatters[$this->format])) {
        $formatter = $this->formatters[$this->format];
        if (!is_object($formatter)) {
            $this->formatters[$this->format] = $formatter = Yii::createObject($formatter);
        }
        if ($formatter instanceof ResponseFormatterInterface) {
            $formatter->format($this);
        } else {
            throw new InvalidConfigException("The "{$this->format}" response formatter is invalid. It must implement the ResponseFormatterInterface.");
        }
    } elseif ($this->format === self::FORMAT_RAW) {
        if ($this->data !== null) {
            $this->content = $this->data;
        }
    } else {
        throw new InvalidConfigException("Unsupported response format: {$this->format}");
    }
    
 
    //確保響應(yīng)的content為string
    if (is_array($this->content)) {
        throw new InvalidParamException("Response content must not be an array.");
    } elseif (is_object($this->content)) {
        if (method_exists($this->content, "__toString")) {
            $this->content = $this->content->__toString();
        } else {
            throw new InvalidParamException("Response content must be a string or an object implementing __toString().");
        }
    }
}


protected function sendHeaders()
{
    //判斷是否已經(jīng)把頭部發(fā)送出去了
    if (headers_sent()) {
        return;
    }
    if ($this->_headers) {
        $headers = $this->getHeaders();
        //設(shè)置并發(fā)送http響應(yīng)頭
        foreach ($headers as $name => $values) {
            $name = str_replace(" ", "-", ucwords(str_replace("-", " ", $name)));
            // set replace for first occurrence of header but false afterwards to allow multiple
            $replace = true;
            foreach ($values as $value) {
                //主要就是調(diào)用了PHP的header()函數(shù)
                header("$name: $value", $replace);
                $replace = false;
            }
        }
    }
    $statusCode = $this->getStatusCode();
    header("HTTP/{$this->version} {$statusCode} {$this->statusText}");
    //主要就是調(diào)用了PHP的setcookie()函數(shù)
    $this->sendCookies();
}


protected function sendContent()
{
    if ($this->stream === null) {
        //直接echo輸出內(nèi)容
        echo $this->content;

        return;
    }

    set_time_limit(0); // Reset time limit for big files
    $chunkSize = 8 * 1024 * 1024; // 8MB per chunk

    if (is_array($this->stream)) {
        list ($handle, $begin, $end) = $this->stream;
        fseek($handle, $begin);
        while (!feof($handle) && ($pos = ftell($handle)) <= $end) {
            if ($pos + $chunkSize > $end) {
                $chunkSize = $end - $pos + 1;
            }
            echo fread($handle, $chunkSize);
            flush(); // Free up memory. Otherwise large files will trigger PHP"s memory limit.
        }
        fclose($handle);
    } else {
        while (!feof($this->stream)) {
            echo fread($this->stream, $chunkSize);
            flush();
        }
        fclose($this->stream);
    }
}


請(qǐng)求流程

聲明:以下內(nèi)容轉(zhuǎn)載自‘http://www.yiichina.com/doc/g...’


1.用戶向入口腳本 web/index.php 發(fā)起請(qǐng)求。

2.入口腳本加載應(yīng)用配置并創(chuàng)建一個(gè)應(yīng)用實(shí)例去處理請(qǐng)求。

3.應(yīng)用通過請(qǐng)求組件解析請(qǐng)求的路由。

4.應(yīng)用創(chuàng)建一個(gè)控制器實(shí)例去處理請(qǐng)求。

5.控制器創(chuàng)建一個(gè)操作實(shí)例并針對(duì)操作執(zhí)行過濾器。

6.如果任何一個(gè)過濾器返回失敗,則操作退出。

7.如果所有過濾器都通過,操作將被執(zhí)行。

8.操作會(huì)加載一個(gè)數(shù)據(jù)模型,或許是來(lái)自數(shù)據(jù)庫(kù)。

9.操作會(huì)渲染一個(gè)視圖,把數(shù)據(jù)模型提供給它。

10.渲染結(jié)果返回給響應(yīng)組件。

11.響應(yīng)組件發(fā)送渲染結(jié)果給用戶瀏覽器。


應(yīng)用主體生命周期

聲明:以下內(nèi)容轉(zhuǎn)載自"http://www.yiichina.com/doc/guide/2.0/structure-applications"
在深入研究了源碼之后,在此總結(jié)一下。當(dāng)運(yùn)行入口腳本處理請(qǐng)求時(shí), 應(yīng)用主體會(huì)經(jīng)歷以下生命周期:

入口腳本加載應(yīng)用主體配置數(shù)組。

入口腳本創(chuàng)建一個(gè)應(yīng)用主體實(shí)例:

  a.調(diào)用 preInit() 配置幾個(gè)高級(jí)別應(yīng)用主體屬性, 比如 yiiaseApplication::basePath。
  b.注冊(cè) yiiaseApplication::errorHandler 錯(cuò)誤處理方法.
  c.配置應(yīng)用主體屬性.
  d.調(diào)用 init() 初始化,該函數(shù)會(huì)調(diào)用 bootstrap() 運(yùn)行引導(dǎo)啟動(dòng)組件.

入口腳本調(diào)用 yiiaseApplication::run() 運(yùn)行應(yīng)用主體:

   a.觸發(fā) EVENT_BEFORE_REQUEST 事件。
   b.處理請(qǐng)求:解析請(qǐng)求 路由 和相關(guān)參數(shù); 創(chuàng)建路由指定的模塊、控制器和動(dòng)作對(duì)應(yīng)的類,并運(yùn)行動(dòng)作。
   c.觸發(fā) EVENT_AFTER_REQUEST 事件。
   d.發(fā)送響應(yīng)到終端用戶.

入口腳本接收應(yīng)用主體傳來(lái)的退出狀態(tài)并完成請(qǐng)求的處理。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/26026.html

相關(guān)文章

  • Yii2框架源碼分析之如何實(shí)現(xiàn)注冊(cè)和登錄

    摘要:在用戶注冊(cè)的時(shí)候是為空的,當(dāng)用戶忘記密碼在登錄頁(yè)面點(diǎn)擊后生成的,用來(lái)給用法發(fā)送郵件后重置密碼時(shí)進(jìn)行驗(yàn)證。如有錯(cuò)誤,不吝賜教。 注冊(cè) 在advanced模板中,進(jìn)入frontend/index.php?r=site%2Fsignup頁(yè)面,可以看到框架的注冊(cè)頁(yè)面showImg(https://segmentfault.com/img/bVDEaZ?w=300&h=235); 填寫完User...

    chemzqm 評(píng)論0 收藏0
  • Yii2源碼分析輔助記錄

    get_called_class get_class call_user_func strncmp method_exists property_exists array_unshift get_class

    馬龍駒 評(píng)論0 收藏0
  • yii2框架中的di容器源碼中了解反射的作用

    摘要:反射簡(jiǎn)介參考官方簡(jiǎn)介的話,具有完整的反射,添加了對(duì)類接口函數(shù)方法和擴(kuò)展進(jìn)行反向工程的能力。此外,反射提供了方法來(lái)取出函數(shù)類和方法中的文檔注釋。 反射簡(jiǎn)介 參考官方簡(jiǎn)介的話,PHP 5 具有完整的反射 API,添加了對(duì)類、接口、函數(shù)、方法和擴(kuò)展進(jìn)行反向工程的能力。 此外,反射 API 提供了方法來(lái)取出函數(shù)、類和方法中的文檔注釋。 YII2框架中示例 對(duì)于yii2框架,應(yīng)該都知道di容器,...

    dantezhao 評(píng)論0 收藏0
  • 列表——表頭自定義顯示字段

    摘要:今天我就來(lái)講講插件的使用,它是如何實(shí)現(xiàn)列表表頭自定義顯示字段的,我把我的經(jīng)驗(yàn)分享出來(lái),滿足一下不懂英語(yǔ)的人,給你們搭個(gè)快車。需求分析實(shí)現(xiàn)列表表頭自定義顯示字段,自定義表頭排序。 序言 Yii2框架的擴(kuò)展性能真的很不錯(cuò),很多效果都可以通過插件去實(shí)現(xiàn),你想不到的老外都幫你想好了,于是,人群中就流傳了這么一句話:效果不會(huì)寫不要緊,會(huì)用插件也不錯(cuò)。GitHub是一個(gè)龐大而且開放的資源庫(kù),平時(shí)有...

    Yangyang 評(píng)論0 收藏0
  • Yii2系列教程六:集成編輯器

    摘要:而這些問題目前的最好解決方案就是集成一個(gè)編輯器,鑒于大家這里不是指程序員都是喜歡所見即所得,所以,這里我主要是演示怎么集成所見即所得的富文本編輯器。 原文來(lái)自: https://jellybool.com/post/programming-with-yii2-rich-text-input-with-redactor 首先,很慚愧的是,前幾天都出去外面玩了,沒有及時(shí)更新教程,...

    xiaochao 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<