• ThinkPHP6源码分析之应用初始化


    ThinkPHP6 源码分析之应用初始化

    官方群点击此处

    App Construct

    先来看看在 __construct 中做了什么,基本任何框架都会在这里做一些基本的操作,也就是从这里开始延伸出去。

    public function __construct(string $rootPath = '')
    
    {
    
        $this->thinkPath   = dirname(__DIR__) . DIRECTORY_SEPARATOR;
    
        $this->rootPath    = $rootPath ? rtrim($rootPath, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR : $this->getDefaultRootPath();
    
        $this->appPath     = $this->rootPath . 'app' . DIRECTORY_SEPARATOR;
    
        $this->runtimePath = $this->rootPath . 'runtime' . DIRECTORY_SEPARATOR;
    
        if (is_file($this->appPath . 'provider.php')) {
    
            $this->bind(include $this->appPath . 'provider.php');
    
        }
    
        static::setInstance($this);
    
        $this->instance('app', $this);
    
        $this->instance('thinkContainer', $this);
    
    }

    ● 从魔术的方法的参数 rootPath 来看,是支持自定义根目录路径的。

    ● 设置了 thinkPath, rootPath, appPath, runtimePath

    ● 绑定了默认的服务提供者,一共提供了两个,appReques 和 appExceptionHandle,实际上你使用的 Request 就是它。具体到 appPath 查看

    ● 设置当前容器实例 APP

    ● 将 App($this) 实例 绑定到容器中,分别是 app 和 thinkContainer

    这里需要注意的是 App 类是继承 Container 的,所以就是将自身实例绑定到容器中。

    在这里似乎整个应用就已经初始化结束了?这里我需要把一部分 Request run 的内容放在这里说,因为那里才是框架主要的初始化工作,我并不认为将这一部分初始化工作放在 Request run 中是合理的。

    主要的初始化

    public function initialize()
    
    {
    
        $this->initialized = true;
    
        $this->beginTime = microtime(true);
    
        $this->beginMem  = memory_get_usage();
    
        // 加载环境变量
    
        if (is_file($this->rootPath . '.env')) {
    
            $this->env->load($this->rootPath . '.env');
    
        }
    
        $this->configExt = $this->env->get('config_ext', '.php');
    
        $this->debugModeInit();
    
        // 加载全局初始化文件
    
        $this->load();
    
        // 加载框架默认语言包
    
        $langSet = $this->lang->defaultLangSet();
    
        $this->lang->load($this->thinkPath . 'lang' . DIRECTORY_SEPARATOR . $langSet . '.php');
    
        // 加载应用默认语言包
    
        $this->loadLangPack($langSet);
    
        // 监听AppInit
    
        $this->event->trigger('AppInit');
    
        date_default_timezone_set($this->config->get('app.default_timezone', 'Asia/Shanghai'));
    
        // 初始化
    
        foreach ($this->initializers as $initializer) {
    
            $this->make($initializer)->init($this);
    
        }
    
        return $this;
    
    }

    ● 加载 .env 环境变量文件

    ● 加载配置文件以及应用内的文件

    ● 加载应用内的 common.php

    ● 加载助手函数 在 thinkPath 目录下的 helper.php

    ● 加载配置文件

    ● 加载应用目录下的 event.php 事件

    ● 注册应用目录下的 service.php 服务

    ● 加载语言包

    ● 监听 AppInit 事件,利用该事件可以做一些请求前的工作

    ● 设置时区

    ● 注入所有服务并且启动服务

    服务注册

    初始化过程中,进行服务注册,那么服务注册做了哪些事情呢?该如何使用的服务呢?

    public function register($service, bool $force = false)
    
    {
    
        $registered = $this->getService($service);
    
        if ($registered && !$force) {
    
            return $registered;
    
        }
    
        if (is_string($service)) {
    
            $service = new $service($this);
    
        }
    
        if (method_exists($service, 'register')) {
    
            $service->register();
    
        }
    
        if (property_exists($service, 'bind')) {
    
            $this->bind($service->bind);
    
        }
    
        $this->services[] = $service;
    
    }

    ● 服务是否注册过,如果需要强制重新注册

    ● 实例化服务

    ● 如果实现了 register 方法,则需要执行 register 方法

    ● 如果设置了 bind 属性,则需要将 service 实例绑定到容器

    ● 最后合并到整个 service 数组中,等待 boot

    服务启动

    目前在初始化的时候只有下面三个服务,在 $this->initializers 数组中

    foreach ($this->initializers as $initializer) {
    
            $this->make($initializer)->init($this);
    
    }

    这三个服务分别是:

    thinkinitializerBootService
    
    thinkinitializerError
    
    thinkinitializerRegisterService
    

    ● Error 服务是用来处理框架异常和错误的

    ● RegisterService 从字面的意思就是注册服务的

    ● BootService 就是启用服务的

    Error 处理在之后再说,这里说一下 RegisterService 和 BootService。

    当从 Container 中 make 出 RegisterService 的时候

    这里有个隐藏的静态方法 make,每次如果首次从 Container 中 make 出来的实例对象都会执行 make 方法,当然首先必须你实现了该方法。

    随后会执行 Init 方法。当你进入到 RegisterService 的时候,你会看到该方法。方法内容如下:

    public function init(App $app)
    
    {
    
        $file = $app->getRootPath() . 'runtime' . DIRECTORY_SEPARATOR . 'services.php';
    
        $services = $this->services;
    
        if (is_file($file)) {
    
            $services = array_merge($services, include $file);
    
        }
    
        foreach ($services as $service) {
    
            if (class_exists($service)) {
    
                $app->register($service);
    
            }
    
        }
    
    }

    该方法就很奇怪了,和我想象的有点不一样。服务是直接从 runtime 目录下面获取的,而非在 config 目录下的 service.php 中。为什么会这样呢?由于 composer 的发展,TP 框架也可以提供包的自动发现的功能,这也证明了开发组在不断向社区靠拢。下面来看一下是如何实现的。

    因为这都是得益于 composer 的,所以来看一下 rootPath 下的 composer.json,到最下面,你会发现下面的配置

    "scripts": {
    
        "post-autoload-dump": [
    
            "@php think service:discover",
    
            "@php think vendor:publish"
    
        ]
    
    }

    从配置来看,框架一共提供了两个指令,service:discover 和 vendor:publish。具体实现这里就不说了,你只需要知道包的发现是由 service:discover 实现的。

    还有就是这里默认注入了三个服务。

    PaginatorService::class,
    
    ValidateService::class,
    
    ModelService::class,

    最后再来看看 BootService,这个就很简单了。从命名来讲就不难看出,下面就是代码,正常的启动服务,但是这里要说明的是,服务类中必须实现了 boot 方法才会启动。

    public function init(App $app)
    
    {
    
        $app->boot();
    
    }

    以上就是ThinkPHP6源码分析之应用初始化的详细内容

    以上内容希望帮助到大家,很多PHPer在进阶的时候总会遇到一些问题和瓶颈,业务代码写多了没有方向感,不知道该从那里入手去提升,对此我整理了一些资料,包括但不限于:分布式架构、高可扩展、高性能、高并发、服务器性能调优、TP6,laravel,YII2,Redis,Swoole、Swoft、Kafka、Mysql优化、shell脚本、Docker、微服务、Nginx等多个知识点高级进阶干货需要的可以免费分享给大家,需要的可以加入我的官方群点击此处

  • 相关阅读:
    Oracle记录-Linux JDK与Oracle profile环境配置
    MySQL记录-Lost Connect MySQL Server during query解决方案
    Hive记录-配置远程连接(JAVA/beeline)
    CM记录-Hadoop 分布式文件系统HDFS(登录、配置、监控)
    currentStyle
    封装用className选元素
    event
    jQuery全局函数
    ajax请求
    [Swift-2019力扣杯春季决赛]1. 有序数组中的缺失元素
  • 原文地址:https://www.cnblogs.com/a609251438/p/12109662.html
Copyright © 2020-2023  润新知