本文从入口文件的请求内容到简要分析响应组件将结果发送到用户浏览器的过程。流程分析从入口文件进入,直接看重点,分析应用的启动流程$config=require__DIR__.'/../config/web.php';(newyii\web\Application($配置))->运行();首先进入没有构造函数的yii\web\Application类,即找到父类\yii\base\Applicationpublicfunction__construct($config=[]){//保存当前启动的应用实例,交给Yii::$appYii::$app=$this;静态::设置实例($this);$this->state=self::STATE_BEGIN;$this->preInit($config);//加载异常处理,这个比较深,后面会展开。$this->registerErrorHandler($config);Component::__construct($config);}让我们看看static::setInstance($this);指向yii\base\ModulepublicstaticfunctionsetInstance($instance){//将当前实例添加到Yii::$app->loadedModules['yii\web\Application']数组中if($instance===null){unset(Yii::$app->loadedModules[get_called_class()]);}else{Yii::$app->loadedModules[get_class($instance)]=$instance;}}这个主要是后面用到的,比如在模块中,通过self::getInstance()获取App对象,类似Yii::$app。(后面可以再深入)接下来看$this->preInit($config);这里是加载配置文件的框架信息,比如:设置别名,设置框架路径等,最重要的是加载默认组件foreach($this->coreComponents()as$id=>$component){如果(!isset($config['components'][$id])){$config['components'][$id]=$component;}elseif(is_array($config['components'][$id])&&!isset($config['components'][$id]['class'])){$config['components'][$id]['类']=$组件['类'];}}然后是Component::__construct($config);publicfunction__construct($config=[]){if(!empty($config)){Yii::configure($this,$config);//本地修改配置文件中的所有配置信息}$this->init();//移除controller的命名空间(路径)}至此,第一部分已经执行完毕,开始执行$application->run()publicfunctionrun(){try{$this->state=self::STATE_BEFORE_REQUEST;//加载事件函数。和狗子类似,后面我们会深入分析。$this->trigger(self::EVENT_BEFORE_REQUEST);$this->state=self::STATE_HANDLING_REQUEST;//重中之重-加载控制器$response=$this->handleRequest($this->getRequest());$this->state=self::STATE_AFTER_REQUEST;$this->trigger(self::EVENT_AFTER_REQUEST);//加载事件函数$this->state=self::STATE_SENDING_RESPONSE;$response->send();//将页面内容输出$this->state=self::STATE_END;返回$response->exitStatus;}catch(ExitException$e){$this->end($e->statusCode,isset($response)?$response:null);返回$e->statusCode;}}我们来看下面$response=$this->handleRequest($this->getRequest());publicfunctionhandleRequest($request){if(empty($this->catchAll)){try{list($route,$params)=$request->resolve();}catch(UrlNormalizerRedirectException$e){$url=$e->url;if(is_array($url)){if(isset($url[0])){//确保路由是绝对的$url[0]='/'.ltrim($url[0],'/');$url+=$request->getQueryParams();}返回$this->getResponse()->redirect(Url::to($url,$e->scheme),$e->statusCode);}}else{$route=$this->catchAll[0];$params=$this->catchAll;取消设置($params[0]);}try{Yii::debug("请求路由:'$route'",__METHOD__);$this->requestedRoute=$route;$result=$this->runAction($route,$params);如果($resultinstanceofResponse){return$result;}$response=$this->getResponse();如果($result!==null){$response->data=$result;}返回$响应;}catch(InvalidRouteException$e){thrownewNotFoundHttpException(Yii::t('yii','找不到页面'),$e->getCode(),$e);}}我们再看这句话指向:\yii\base\Module的runActionpublicfunctionrunAction($route,$params=[]){$parts=$this->createController($route);if(is_array($parts)){/*@var$controller控制器*/list($controller,$actionID)=$parts;$oldController=Yii::$app->controller;Yii::$app->controller=$controller;$result=$controller->runAction($actionID,$params);如果($oldController!==null){Yii::$app->controller=$oldController;}返回$结果;$id=$this->getUniqueId();thrownewInvalidRouteException('无法解析请求“'。($id===''?$route:$id.'/'.$route).'”.');}最后是$response->send();publicfunctionsend(){if($this->isSent){return;}$this->trigger(self::EVENT_BEFORE_SEND);//获取$response的格式,然后执行格式对象格式方法的实例(header设置Content-Type)$this->prepare();$this->trigger(self::EVENT_AFTER_PREPARE);$this->sendHeaders();$this->sendContent();$this->trigger(self::EVENT_AFTER_SEND);$this->isSent=true;}总结yii给出的运行机制概述和图解,描述应用程序如何处理一个请求
