Yii2 分析运行流程

简介: 版本创建Applicationrun过程handleRequestrunAction简述流程1 版本// yii\BaseYii\getVersionpublic static function getVersion(){ return '2.0.10';}2 创建Application// web/

1 版本

// yii\BaseYii\getVersion
public static function getVersion()
{
    return '2.0.10';
}

2 创建Application

// web/index.php

new yii\web\Application($config)

创建一个app用于处理本次请求

// yii\base\Application.php

public function __construct($config = [])
{
    Yii::$app = $this;
    static::setInstance($this);

    $this->state = self::STATE_BEGIN;
    // 配置属性
    $this->preInit($config);
    // 注册error相关处理函数
    $this->registerErrorHandler($config);
    // 在基类的构造函数中将会调用init()函数
    // 在init()中直接调用bootstrap()函数
    // 先调用 web/Application::bootstrap()
    // 再调用 base/Application::bootstrap()
    Component::__construct($config);
}
//  base/Application::bootstrap()

protected function bootstrap()
{
    // 加载扩展清单中的文件, 默认使用 vendor/yiisoft/extensions.php
    if ($this->extensions === null) 
    {
        $file = Yii::getAlias('@vendor/yiisoft/extensions.php');
        $this->extensions = is_file($file) ? include($file) : [];
    }
    // 创建这些扩展组件
    // 如果这些组件实现了BootstrapInterface, 还会调用组件下的bootstrap函数
    foreach ($this->extensions as $extension)
    {
        if (!empty($extension['alias'])) 
        {
            foreach ($extension['alias'] as $name => $path) 
            {
                Yii::setAlias($name, $path);
            }
        }
        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__);
            }
        }
    }

    // 加载将要运行的一些组件, 这些组件配置在main.php, main-local.php中
    // 'bootstrap' => ['log'],
    // $config['bootstrap'][] = 'debug';
    // $config['bootstrap'][] = 'gii';
    // 开发模式下,默认加载3个: log, debug, gii
    // 从$config中的配置信息变成base\Application中的属性$bootstrap经历以下步骤:
    // Component::__construct  --> Yii::configure($this, $config)

    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);
        }
        // 如果这些组件实现了BootstrapInterface, 还会调用组件下的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__);
        }
    }
}

3 run过程

整个run过程经历以下过程:

public function run()
{
    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;
        return $response->exitStatus;
    } catch (ExitException $e) {
        $this->end($e->statusCode, isset($response) ? $response : null);
        return $e->statusCode;
    }
}

4 handleRequest

public function handleRequest($request)
{
    // 如果设置了catchAll变量, 那么所有请求都会跳转到这里
    // 示例:
    // 假设网站维护, 不希望有人访问到内容
    // 可以创建一个OfflineController控制器, 对应的views/offline/index.php可以写上
    // <h1>网站正在维护中</h1>
    // 然后在main.php中的$config中添加以下内容
    // 'catchAll' => [ 'offline/index']
    // 这样, 所有的访问都跳转到 网站正在维护中 的页面了

    if (empty($this->catchAll)) 
    {
        try 
        {
            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();
            }
            return $this->getResponse()->redirect(Url::to($url, $e->scheme), $e->statusCode);
        }
    } 
    // 跳转到catchAll指定的route
    else 
    {
        $route = $this->catchAll[0];
        $params = $this->catchAll;
        unset($params[0]);
    }
    try 
    {
        Yii::trace("Route requested: '$route'", __METHOD__);
        $this->requestedRoute = $route;
        $result = $this->runAction($route, $params);
        ...
    }
    ...
}

5 runAction

创建Controller,并执行Controller对应的action

public function runAction($route, $params = [])
{
    // 创建Controller
    $parts = $this->createController($route);
    if (is_array($parts)) 
    {
        list($controller, $actionID) = $parts;
        $oldController = Yii::$app->controller;
        Yii::$app->controller = $controller;

        // 执行controller中的action
        $result = $controller->runAction($actionID, $params);
        if ($oldController !== null) 
        {
            Yii::$app->controller = $oldController;
        }
        return $result;
    } 
    else 
    {
        $id = $this->getUniqueId();
        throw new InvalidRouteException('Unable to resolve the request "' . ($id === '' ? $route : $id . '/' . $route) . '".');
    }
}

6 简述流程

  • 通过Application创建app, 并且读入config, 装载扩展和组件
  • 通过request解析被请求的路由
  • app根据路由创建controller
  • controller创建action
  • 如果过滤器通过, 则会执行action
  • action会渲染视图view
  • view中的内容一般来自于model
  • 渲染的结果通过response返回给客户端
相关文章
|
5月前
|
JSON 数据格式 容器
SpringMVC运行流程分析之核心流程
SpringMVC运行流程分析之核心流程
17 0
|
2月前
|
移动开发 小程序 数据管理
9月开发者日回顾|小程序跳转接口等多个JSAPI更新,能力集成提供场景化排查工具
9月开发者日回顾|小程序跳转接口等多个JSAPI更新,能力集成提供场景化排查工具
27 0
|
6月前
|
敏捷开发 存储 JSON
在低代码平台执行 API 请求并将结果显示在页面上
在低代码平台执行 API 请求并将结果显示在页面上
47 0
|
11月前
|
网络安全 Windows
基于fastapi实现6个接口(token拦截, 2个业务流程,接口参数依赖校验)已经通过postman测试,记录部署服务器和windows,用于pytest接口自动化框架的接口测试对象
基于fastapi实现6个接口(token拦截, 2个业务流程,接口参数依赖校验)已经通过postman测试,记录部署服务器和windows,用于pytest接口自动化框架的接口测试对象
|
SQL 安全 算法
使用yii2.0,如何让自己的项目安全最大化,具体步骤是怎样的?
使用yii2.0,如何让自己的项目安全最大化,具体步骤是怎样的?
|
缓存 前端开发 JavaScript
如何优化Yii2视图文件的加载速度?具体步骤是怎样的?底层原理是什么?
如何优化Yii2视图文件的加载速度?具体步骤是怎样的?底层原理是什么?
104 0
jira学习案例39-加载中和错误的处理
jira学习案例39-加载中和错误的处理
63 0
jira学习案例39-加载中和错误的处理
|
PHP 开发工具 数据库
Yii2 修改框架入口增加配置适应开发生产环境
Yii2 修改框架入口增加配置适应开发生产环境
91 0
Yii2 修改框架入口增加配置适应开发生产环境
|
存储 安全 PHP
【Laravel】在企业级项目中使用Laravel框架中的工厂状态下的页面方法 Code Verifier以及错误处理
【Laravel】在企业级项目中使用Laravel框架中的工厂状态下的页面方法 Code Verifier以及错误处理
102 0
【Laravel】在企业级项目中使用Laravel框架中的工厂状态下的页面方法 Code Verifier以及错误处理
|
数据安全/隐私保护
Appium自动化框架从0到1之 业务模块封装(登录页面业务操作)
Appium自动化框架从0到1之 业务模块封装(登录页面业务操作)
111 0
Appium自动化框架从0到1之 业务模块封装(登录页面业务操作)