• yii2 源码分析1从入口开始





    我是在 backend 一步步打印的 很多地方我也是很模糊 。后来发现一位大神的文章(http://www.yiichina.com/tutorial/773) 参考文章自己动手开始写的 至于后来的 第一遍 很粗糙 慢慢完善。
    希望对自己有帮助 希望各位积极指点 和后面不详细的地方 作补充。 我也会继续完善 。

    先从入口开始
    $application
    = new yiiwebApplication($config);  //实例化 Application
    $application->run();

    这是  Application 的方法
    class Application extends yiiaseApplication   
    在Application类中 首先看有没有构造方法  没有找到  so  就去父类中找(yiiaseApplication)


    在yiiaseApplication  
    ..........
        public function __construct($config = [])
        {
            Yii::$app = $this;  // $this  代表  object(yiiwebApplication)
            static::setInstance($this);  //  在这个方法中把这个类中所有的方法属性都放到一个数组中@@@@@请看下面
    
            $this->state = self::STATE_BEGIN;
    
            $this->preInit($config);  //看下面有解释
    
            $this->registerErrorHandler($config);//暂不做解释  加载异常类  以后研究  
    
            Component::__construct($config);
        }
    ..........
    @@@@@
    public static function setInstance($instance)
    {
    if ($instance === null) {    //$instance不为空 代表的$this(object(yiiwebApplication))
            unset(Yii::$app->loadedModules[get_called_class()]);
    } else {              //get_class($instance) -> "yiiwebApplication"
    Yii::$app->loadedModules[get_class($instance)] = $instance;
    }
    }
    这样 Yii::$app 就可以调用 该类中的方法 属性 以及父类中的方法。

    $this->preInit($config);// 

    *****preInit****方法

    主要是获取到配置文件中的数据  处理配置文件的数据 设置别名等等
    public function preInit(&$config)
    {
    if (!isset($config['id'])) {
    throw new InvalidConfigException('The "id" configuration for the Application is required.');
    }
    if (isset($config['basePath'])) {
    $this->setBasePath($config['basePath']); //拿这个做例子
    unset($config['basePath']);

    。。。部分代码省略。。。。。
      
      public function setBasePath($path)
      {              
          var_dump($path);die;   //     "/var/www/testyii2/backend"     
       parent::setBasePath($path);     //该方法中设置 $this->_basePath = $app;  $app=/var/www/testyii2/backend
          Yii::setAlias('@app', $this->getBasePath());   so  此时  @app  就等于  /var/www/testyii2/backend
      }
    好了现在回到 preInit()方法中
    *******end*****
    $this->registerErrorHandler($config);简单看下吧
    $this->set('errorHandler', $config['components']['errorHandler']);
    我打印了下 var_dump($this->get('errorHandler')) 应该是 定义一些错误方法和属性等等 看下图
    
    
    最后看这个方法
    Component::__construct($config);  调用了 object 方法中的 构造方法
    object(类):
    public function __construct($config = [])
    {
    if (!empty($config)) {
    Yii::configure($this, $config);  //找到Yii类 该类中没有configure 方法 然而继承了 baseyii so 去baseyii类中找
                              //
    }
    $this->init();
    }
    。。。。。
    //baseyii类
    public static function configure($object, $properties)
    {
    foreach ($properties as $name => $value) {
    $object->$name = $value;
    }
    return $object;
    }
    //该方法 中 $object ==object类 循环吧配置文件中的 数据 复制给 object对象中的属性和值  最终由于object 是yiiwebApplication 的最终父类 还有在上面中定义了别名@app

      // so  可以Yii::$app->配置参数来访问配置文件中的内容

    ****end***

    分析
    $this->init();  在object类中   class Component extends Object  component继承的object
    Component::__construct($config);   在base/Application  继承了 Module 类 
    so 看module 中的init方法()
    //module 中的init 方法   
        public function init()
        {
            if ($this->controllerNamespace === null) {  //取出控制器命名空间。
                $class = get_class($this);
                if (($pos = strrpos($class, '\')) !== false) {
                    $this->controllerNamespace = substr($class, 0, $pos) . '\controllers';
                }
            }
        }

    完毕

    回到起点 看index.php中的

    $application->run();   在Application类中没有找到run方法   Application 继承 baseApplication类

    yiiaseApplication.php   中的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调用的是  yiiwebApplication.php 中的方法看下面
            $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; }
          }
    //web/Application 中的 handleRequest()
        public function handleRequest($request)
        {
            if (empty($this->catchAll)) {
                list ($route, $params) = $request->resolve();  //取出路由及参数
            } 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);//运行控制器中的Acition,下面有详细介绍    base/application 中没有so 找到module 中的runaction()
    if ($result instanceof Response) {
                    return $result;
                } else {
                    $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);
            }
        }
    // class Module
    
    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);//创建方法执行控制器里的action  actionId ==index( 控制器/index(这里表示方法))
                Yii::$app->controller = $oldController;
    
                return $result;
            } else {
                $id = $this->getUniqueId();
                throw new InvalidRouteException('Unable to resolve the request "' . ($id === '' ? $route : $id . '/' . $route) . '".');
            }
        }
    $this->createController()
    $this->createController()  //创建控制器
    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 = '';
            }
    echo   $route  //--->"backend/default/index"
    // 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);
    }

    if (($pos = strrpos($route, '/')) !== false) {
    $id .= '/' . substr($route, 0, $pos);  
    $route = substr($route, $pos + 1);  
    }
    //$id = backend/default"   (模块/控制器)   $route =index   方法
        $controller = $this->createControllerByID($id);  //下面分析用颜色查找
    if ($controller === null && $route !== '') {  //进入
    $controller = $this->createControllerByID($id . '/' . $route); // 根据给定的控制器标识创建一个控制器。看下面
    $route = '';
    }

    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);    //backend 模块
    $className = substr($id, $pos + 1);    //default 控制器
    }

    if (!preg_match('%^[a-z][a-z0-9\-_]*$%', $className)) {
    return null;
    }
    // preg_match('%^[a-z0-9_/]+$%i', $prefix) ===1
        if ($prefix !== '' && !preg_match('%^[a-z0-9_/]+$%i', $prefix)) {      
            return null;
    }
        $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 = Yii::createObject($className, [$id, $this]);  //创建了控制器对象
    return get_class($controller) === $className ? $controller : null;
    } elseif (YII_DEBUG) {
    throw new InvalidConfigException("Controller class must extend from \yii\base\Controller.");
    } else {
    return null;
    }
    }
    Yii/BaseYii.php

    public static function createObject($type, array $params = [])
    {
    if (is_string($type)) {
    return static::$container->get($type, $params);  //返回请求类的是例 这边就不往下追了 本人能力有限啊 唉~无线惆怅中~~~
    } elseif (is_array($type) && isset($type['class'])) {
    $class = $type['class'];
    unset($type['class']);
    return static::$container->get($class, $params, $type);
    } elseif (is_callable($type, true)) {
    return static::$container->invoke($type, $params);
    } elseif (is_array($type)) {
    throw new InvalidConfigException('Object configuration must be an array containing a "class" element.');
    } else {
    throw new InvalidConfigException('Unsupported configuration type: ' . gettype($type));
    }
    }
    ****end** 小部分结束(创建控制器部分)
    //承接上面的方法继续分析
    $controller->runAction($actionID, $params);
    namespace  yiiase;   //命名空间
    class Controller extends Component implements ViewContextInterface{
    public function runAction($id, $params = [])
    {
      $action = $this->createAction($id);  ////创建action  暂时不补全代码了 类啊。。。后续补上。
      //打印$action == yiiaseInlineAction 对象

       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;    //NULL
      $this->action = $action;

      $modules = [];
      $runAction = true;

      // call beforeAction on modules   // 加载默认模块如:Application log等。再调用模块内的beforeAction方法
      foreach ($this->getModules() as $module) {
       if ($module->beforeAction($action)) {
       array_unshift($modules, $module);
       } else {
       $runAction = false;
       break;
       }
      }

    $result = null;

    if ($runAction && $this->beforeAction($action)) { //执行beforeAction
    // run the action
    $result = $action->runWithParams($params);   //执行控制器里的action

    $result = $this->afterAction($action, $result); //执行afterAction


    // call afterAction on modules
    foreach ($modules as $module) {
    /* @var $module Module */
    $result = $module->afterAction($action, $result);
    }
    }

    $this->action = $oldAction;

    return $result;
    }
    }

    //打印action yiiaseInlineAction
    public function runWithParams($params)
    {
    $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;
    }

    return call_user_func_array([$this->controller, $this->actionMethod], $args);
    }
  • 相关阅读:
    解决SQL Server Compact 无法在64位系统下正常运行
    Mvc5+Entity Framework6 之二----在MVC中用Entity Framework实现基本的CRUD
    Asp.net MVC5中Html.DropDownList的使用
    C# 使用微软的Visual Studio International Pack 类库提取汉字拼音首字母
    MVC学习 (二) Razor语法
    MVC学习 (一)
    编程实现机器人相遇
    jquery优化引发的思考
    (续)检测到有潜在危险的 Request.Form 值
    检测到有潜在危险的 Request.Form 值
  • 原文地址:https://www.cnblogs.com/yhl664123701/p/5532135.html
Copyright © 2020-2023  润新知