zoukankan      html  css  js  c++  java
  • 【thinkphp6源码分析四】 贯穿流程的Web应用管理类--Http类

    前面讲了那么多 实际都只是在分析在分析入口文件index.php代码的第一句

    $http = (new App())->http;

    甚至连第一句都没完  只是分析了第一句的前半部分  下面我们看下第一句的后半部分  也就是http [tp6vendor opthinkframeworksrc hinkHttp.php]这个类

    首先看这个类的构造函数

      public function __construct(App $app)
        {
            $this->app = $app;
    
            $this->routePath = $this->app->getRootPath() . 'route' . DIRECTORY_SEPARATOR;
        }

    这里能看到 构造函数是需要带入一个 $app 参数的

    那么这里实际就有一个一开始遗留的问题 为什么  (new App())->http; 这样写 能得到http这个类实例呢? 按照常规思路

    我们得到http这个实例 应该  new Http(App $app) 这样才对呀

    对于这个问题 如果前三章思路捋顺的话 这个问题可以自己找到答案  这里 我们再过一次这个流程
    (1)首先 new App 得到 App对象实例  我们定义这个实例为$app 即 $app = new App();

    (2) (new App())->http 则是获取 这个实例的http的属性 这个属性 我们找了APP类没有 它的父类也没有

    (3)所以 需要找到魔术方法  __get()

      (4)  追溯__get的流程  最终是调用了make方法

    (5)make方法传入http 也就是$app->make("http")

      (6)  由于http 可以在 $bind里面找到对应的别名 Http::class  也就是 thinkhttp

      (7) 那么这里就相当于 $app->make("thinkhttp")

    (8)根据上章的讲解和最后的例子 可以知道  这时候 就相当于 new Http()了

    这样 就得到http这个类了

    【这里实际还是有个疑问  正常 我们应该得到  new Http(App $app) 这样才对呀 构造函数里面必须带入$app这个参数   关于这一点 具体还是要解析make用法 后面会详细讲到 】

    构造函数第二句 比较简单 也是定义了一个类似全局变量的东西    $this->routePath = $this->app->getRootPath() . 'route' . DIRECTORY_SEPARATOR;  这里是定义了路由(route)的目录

    关于http类 它的方法不是很多 但每一个都相当抽象 针对这种抽象的功能 我建议我们还是从所见记得的实际例子出发 那样会更好理解一点

    至于实际例子  index.php文件 的第二句就是了 

    $response = $http->run();这里可以看到  系统调用了http类的run方法 那么我们就从run方法入手 来了解这个类

     run方法如下

      public function run(Request $request = null): Response
        {
            //初始化
            $this->initialize();
    
            //自动创建request对象
            $request = $request ?? $this->app->make('request', [], true);
            $this->app->instance('request', $request);
    
            try {
                $response = $this->runWithRequest($request);
            } catch (Throwable $e) {
                $this->reportException($e);
    
                $response = $this->renderException($request, $e);
            }
    
            return $response;
        }
    View Code

    它的第一句$this->initialize()    initialize这个单词是初始化的意思 可以推测这里是进行了一些初始化的流程

    我们追溯这个函数 能看到 它最终是在app类里面的initialize方法

     1  public function initialize()
     2     {
     3         $this->initialized = true;
     4 
     5         $this->beginTime = microtime(true);
     6         $this->beginMem  = memory_get_usage();
     7 
     8         // 加载环境变量
     9         if (is_file($this->rootPath . '.env')) {
    10             $this->env->load($this->rootPath . '.env');
    11         }
    12 
    13         $this->configExt = $this->env->get('config_ext', '.php');
    14 
    15         $this->debugModeInit();
    16 
    17         // 加载全局初始化文件
    18         $this->load();
    19 
    20         // 加载框架默认语言包
    21         $langSet = $this->lang->defaultLangSet();
    22 
    23         $this->lang->load($this->thinkPath . 'lang' . DIRECTORY_SEPARATOR . $langSet . '.php');
    24 
    25         // 加载应用默认语言包
    26         $this->loadLangPack($langSet);
    27 
    28         // 监听AppInit
    29         $this->event->trigger(AppInit::class);
    30 
    31         date_default_timezone_set($this->config->get('app.default_timezone', 'Asia/Shanghai'));
    32 
    33         // 初始化
    34         foreach ($this->initializers as $initializer) {
    35             $this->make($initializer)->init($this);
    36         }
    37 
    38         return $this;
    39     }
    View Code

    我们可以详细看下这个加载流程

    (1)第一句 $this->initialized = true

    这个是为了提高性能用, 方式就类似我们常见的缓存使用  if has  then return xxx  else set xxx  有初始化过 下次再运行到这里 就不用再继续运行 否则进行初始化

    这里也能说明  这个函数  框架会在执行的过程中 重复使用多次(至少2次) 我们也可以留一下 后面哪些流程 会导致这里第二次执行

    (2)定义一些开始标量  开始时间 程序 开始的内存情况 这种一般是为了统计框架性能使用

    $this->beginTime = microtime(true);
    $this->beginMem = memory_get_usage();

    (3)加载环境变量  这也就是为什么 TP框架 支持再根目录 写个.env 就可以把.env里面的内容当做配置文件使用

    if (is_file($this->rootPath . '.env')) {
    $this->env->load($this->rootPath . '.env');
    }

    (4)定义一个叫ConfigExt的东西 暂时不知道哪里用到  从字面意思 应该是加载一些额外的配置文件类型,默认是加载php文件的配置

    $this->configExt = $this->env->get('config_ext', '.php');

    (5)初始化调试   

    $this->debugModeInit();

    (6)加载全局初始化文件  这个细节需要看下load()这个函数

    $this->load();
      protected function load(): void
        {
            $appPath = $this->getAppPath();
    
            if (is_file($appPath . 'common.php')) {
                include_once $appPath . 'common.php';
            }
    
            include_once $this->thinkPath . 'helper.php';
    
            $configPath = $this->getConfigPath();
    
            $files = [];
    
            if (is_dir($configPath)) {
                $files = glob($configPath . '*' . $this->configExt);
            }
    
            foreach ($files as $file) {
                $this->config->load($file, pathinfo($file, PATHINFO_FILENAME));
            }
    
            if (is_file($appPath . 'event.php')) {
                $this->loadEvent(include $appPath . 'event.php');
            }
    
            if (is_file($appPath . 'service.php')) {
                $services = include $appPath . 'service.php';
                foreach ($services as $service) {
                    $this->register($service);
                }
            }
        }
    View Code

    可以在看到

    这里首先加载了 app目录下的common.php  --》这就是为什么common.php里面写的全局函数 我们可以直接使用的原因

    然后加载了think目录下的helper函数 位置为 p6vendor opthinkframeworksrchelper.php] 这里是官方提供的一些助手函数,比如我们常用的打印函数 dump

    然后遍历了config目录 把目录下的所有文件都加载进来  ---》这也就是config目录[项目根目录下的config文件夹]下  我们可以分开写多个的原因

    这里也就知道了前面定义的那个configExt是干嘛的  configExt默认定义的是php 也就说这里只会加载config文件夹下面的php后缀文件

    然后分别LoadEvent和register service 这种代码的目的 和一开始我们遇到的加载容器默认的provider作用一致

    分别是加载默认的event事件  这里可以看到是加载与config同级目录下的event.php

    加载service文件  这里可以看到是加载与config同级目录下的service.php

    [关于event事件和service服务  这两个特性  后面会再详细讲解 目前暂时不提]

    (7)接下来是加载框架的语言包 这是Tp框架可以很好的实现多语言的资本

    // 加载框架默认语言包
    $langSet = $this->lang->defaultLangSet();
    $this->lang->load($this->thinkPath . 'lang' . DIRECTORY_SEPARATOR . $langSet . '.php');
    // 加载应用默认语言包
    $this->loadLangPack($langSet);

    (8)监听一个叫APP::init的事件  这里的$this->event 就是第六条里面加载事件生成的 这里代码的意思 

    AppInit这个类我们可以看到 目前是空的,那么这里可以先理解为 在这里埋一个点 这个点的名字 叫appinit 至于这里要干嘛 还没想好  哪天想好了 可以很方便的在这个点插入某些业务

    比如我想要在appinit的时候 写一个日志  那么就可以在AppInit这个类里面 写入相关的代码  这样的好处是 可以比较方便的扩展 并且不破坏框架原有的代码

    $this->event->trigger(AppInit::class);

    (9)接下来设置时区

    date_default_timezone_set($this->config->get('app.default_timezone', 'Asia/Shanghai'));

    (10)加载系统里面已经定义好的一些初始化类

    foreach ($this->initializers as $initializer) {
    $this->make($initializer)->init($this);
    }
    protected $initializers = [
    Error::class,
    RegisterService::class,
    BootService::class,
    ];

    这个$this->intializers我们可以看到 它包含三部分内容 字面意思是对它们三者进行初始化

    这三者的细节后面我们会再详细了解  目前需要先捋清楚这个加载流程

    上面这10个步骤 就是run()方法里面第一句$this->initialize()  初始化的内容

    接下来

    $request = $request ?? $this->app->make('request', [], true);
            $this->app->instance('request', $request);
    
            try {
                $response = $this->runWithRequest($request);
            } catch (Throwable $e) {
                $this->reportException($e);
    
                $response = $this->renderException($request, $e);
            }
    
            return $response;
    View Code

    系统又通过make函数创建了一个request对象

    这个request对象 我们倒是相对比较熟悉

    比如在控制器里面 我们会通过$request->params()来获取get或post过来的参数

    所有的请求  都会通过request来进行一系列的封装和使用

    好吧 必须得去了解下request了...想想这玩意就不会那么简单..既然这样. .那么下一章见吧

    
    




     
     


  • 相关阅读:
    memcached在大负载高并发网站上的应用(转)
    NHibernate in Action(序,前言,致谢)
    php 数据类型
    w3wp 备忘录
    EF实例化Context
    爬虫程序判断是否已抓URL
    NHibenate in Action(目录)
    C#中静态构造函数的学习
    webservice 无法在网页中进行测试问题
    汉诺塔问题C#
  • 原文地址:https://www.cnblogs.com/dk1988/p/14555666.html
Copyright © 2011-2022 走看看