yii2 执行过程简说

分类:Yii2 |

yii2 beta版 执行流程自动加载

1.composer的自动加载

	//composer的加载实现了四种方式,可以看看  	
	require(__DIR__ . '/../../vendor/autoload.php');

composer的自动加载只加载其下载的组件....和yii框架的加载没有任何关系 2.yii的加载

	spl_autoload_register(['Yii', 'autoload'], true, true);  	
	Yii::$classMap = include(__DIR__ . '/classes.php');  	
	Yii::$container = new yiidiContainer;

这里使用spl_autoload_register把Yii::autoload注册成自动加载器,

  • 判断在不在$classMap中,如果有别名获取别名的文件路径

  • 如果不在$classMap中,则去除下划线,使用别名获取文件路径

  • 引入该文件,并判断是不是类或者接口或者trait

public static function autoload($className)
{
    if (isset(static::$classMap[$className])) {
        $classFile = static::$classMap[$className];
        if ($classFile[0] === '@') {
            $classFile = static::getAlias($classFile);
        }
    } elseif (strpos($className, '\\') !== false) {
        $classFile = static::getAlias('@' . str_replace('\\', '/', $className) . '.php', false);
        if ($classFile === false || !is_file($classFile)) {
            return;
        }
    } else {
        return;
    }

    include($classFile);

    if (YII_DEBUG && !class_exists($className, false) && !interface_exists($className, false) && !trait_exists($className, false)) {
        throw new UnknownClassException("Unable to find '$className' in file: $classFile. Namespace missing?");
    }
}

Yii::$classMap中保存的是命名空间和文件实际路径的对应表,默认加载了所有yii提供的类 Yii::$container 实现了依赖注入, Yii::$app 继承serviceLocal..只实现了单例组件,其中属性_components保存的是对象,_definitions保存的是类,匿名函数或者对象

引导前初始化配置

1.检查配置中模块ID是不是存在
2.检查配置中basePath,vendorPath,runtimePath,timeZone是否存在,并设置
3.向配置中添加核心组件配置: 
base:log,view,formatter,i18n,mailer,urlManager,assetManager,security 
web:request,response,session,user,errorHandler 
4.如果启用了YII_ENABLE_ERROR_HANDLER错误处理,则会注册错误处理组件.然后从配置中卸载errorHandler,避免之后的引导再次添加组件.

ini_set('display_errors', false);  //注意这里...          
public function register()
{
    ini_set('display_errors', false);
    set_exception_handler([$this, 'handleException']);
    if (defined('HHVM_VERSION')) {
        set_error_handler([$this, 'handleHhvmError']);
    } else {
        set_error_handler([$this, 'handleError']);
    }
    if ($this->memoryReserveSize > 0) {
        $this->_memoryReserve = str_repeat('x', $this->memoryReserveSize);
    }
    register_shutdown_function([$this, 'handleFatalError']);
}	

5.然后将配置中的值赋给applicaition

属性说明所在文件
$_events使用on xxx 开通注册事件yiibaseComponent
$_behaviors使用 as xxx开头注册行为yiibaseComponent
$_components保存组件单例对象yiidiServiceLocator
$_definitions保存组件的原始数据yiidiServiceLocator
$params参数,是个数组yiibaseModule
$id模块IDyiibaseModule
$module该模块的父模块yiibaseModule
$layout布局yiibaseModule
$controllerMap控制器地图yiibaseModule
$controllerNamespace控制器命名空间yiibaseModule
$defaultRoute默认路由yiibaseModule
$_basePath模块的根目录yiibaseModule
$_viewPath模块的视图目录yiibaseModule
$_layoutPath模块的布局目录yiibaseModule
$_modules子模块yiibaseModule
$_instances这个不常用,获取当前请求模块的实例yiibaseModule
$controllerNamespace'app\controllers'yiibaseApplication
$name应用名称yiibaseApplication
$version版本yiibaseApplication
$charset字符编码.默认utf8yiibaseApplication
$language语言,默认en-USyiibaseApplication
$sourceLanguage源语言yiibaseApplication
$controller当前的控制器实例yiibaseApplication
$layout布局yiibaseApplication
$requestedRoute请求的路由yiibaseApplication
$requestedAction请求的动作yiibaseApplication
$requestedParams请求的参数yiibaseApplication
$extensions扩展yiibaseApplication
$bootstrap引导yiibaseApplication
$state状态yiibaseApplication
$defaultRoute默认路由yiiwebApplication
$catchAll捕捉所有yiiwebApplication
$controller当前控制器实例yiiwebApplication

引导阶段

  • 1.初始化request组件

  • 2.设置@webroot和@web别名

  • 3.加载扩展extensions,如果没有设置extensions会读取@vendor/yiisoft/extensions.php中的扩展并设置别名,如果扩展可引导,则执行其bootstrap方法-----本身来讲扩展概念没什么用处,因为还是依靠modules来加载这些扩展

  • 4.加载bootstrap中设置的组件和模块或者类,如果引导类实现了BootstrapInterface接口则执行bootstrap的方法

运行

  • 触发请求前事件EVENT_BEFORE_REQUEST,yii-debug中注册了该事件

  • 处理请求,如果catchAll不为空,则使用里面的路由.否则的话会解析获得路由和参数,
    然后执行动作action,返回响应Response,或者响应的data数据.

    public function handleRequest($request)
    {
        if (empty($this->catchAll)) {
            list ($route, $params) = $request->resolve();
        } else {
            $route = $this->catchAll[0];
            $params = array_splice($this->catchAll, 1);
        }
        try {
            Yii::trace("Route requested: '$route'", __METHOD__);
            $this->requestedRoute = $route;
            $result = $this->runAction($route, $params);
            if ($result instanceof Response) {
                return $result;
            } else {
                $response = $this->getResponse();
                if ($result !== null) {
                    $response->data = $result;
                }
    
                return $response;
            }
        } catch (InvalidRouteException $e) {
            throw new NotFoundHttpException($e->getMessage(), $e->getCode(), $e);
        }
    }
  • 动作的执行:首先会根据路由创建控制器.然后执行动作.

      
    public function runAction($route, $params = [])
    {
        $parts = $this->createController($route);
        if (is_array($parts)) {
            /* @var $controller Controller */
            list($controller, $actionID) = $parts;
            $oldController = Yii::$app->controller;
            Yii::$app->controller = $controller;
            $result = $controller->runAction($actionID, $params);
            Yii::$app->controller = $oldController;
    
            return $result;
        } else {
            $id = $this->getUniqueId();
            throw new InvalidRouteException('Unable to resolve the request "' . ($id === '' ? $route : $id . '/' . $route) . '".');
        }
    }

    创建控制器

    public function createController($route)
    {
        if ($route === '') {  //路由为空则使用默认路由
            $route = $this->defaultRoute;
        }
    
        // double slashes or leading/ending slashes may cause substr problem
        $route = trim($route, '/');
        if (strpos($route, '//') !== false) {
            return false;
        }
        //分解路由...前两个第一个可能是模块..第二个才是控制器
        if (strpos($route, '/') !== false) {
            list ($id, $route) = explode('/', $route, 2);
        } else {
            $id = $route;
            $route = '';
        }
    
        // module and controller map take precedence
        if (isset($this->controllerMap[$id])) {
            $controller = Yii::createObject($this->controllerMap[$id], [$id, $this]);
            return [$controller, $route];
        }
        $module = $this->getModule($id);
        if ($module !== null) {   //如果有模块,则继续往下面找.这里是递归...能一直查询子模块
            return $module->createController($route);
        }
    
        //执行到最后,没有子模块的时候...则将id加上剩余的路径(可能有多个/文件夹)  
        if (($pos = strrpos($route, '/')) !== false) {
            $id .= '/' . substr($route, 0, $pos);
            $route = substr($route, $pos + 1);
        }
    
        //查看控制器地图...一般控制器地图里的控制器..作为产品临时使用的页面    
        $controller = $this->createControllerByID($id);
        if ($controller === null && $route !== '') {
            $controller = $this->createControllerByID($id . '/' . $route);
            $route = '';
        }
    
        return $controller === null ? false : [$controller, $route];
    }

    获取模块

    public function getModule($id, $load = true)
    {      //这一段是获取子模块的..在运行中是没有作用的..这一小部分可以当方法使用..          
        if (($pos = strpos($id, '/')) !== false) {              // sub-module  
            $module = $this->getModule(substr($id, 0, $pos));
    
            return $module === null ? null : $module->getModule(substr($id, $pos + 1), $load);
        }                //这是返回模块          
        if (isset($this->_modules[$id])) {
            if ($this->_modules[$id] instanceof Module) {
                return $this->_modules[$id];
            } elseif ($load) {
                Yii::trace("Loading module: $id", __METHOD__);
                if (is_array($this->_modules[$id]) && !isset($this->_modules[$id]['class'])) {
                    $this->_modules[$id]['class'] = 'yiibaseModule';
                }
                /* @var $module Module */
                $module = Yii::createObject($this->_modules[$id], [$id, $this]);
                $module->setInstance($module);
    
                return $this->_modules[$id] = $module;
            }
        }
    
        return null;
    }
  • 触发请求后事件EVENT_AFTER_REQUEST,yii未注册事件

  • 响应发送


阅读( 2888 ) |