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('think\Container', $this);

}

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

● 设置了 thinkPath, rootPath, appPath, runtimePath

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

● 设置当前容器实例 APP

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

这里需要注意的是 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);

}

这三个服务分别是:

think\initializer\BootService

think\initializer\Error

think\initializer\RegisterService

● 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等多个知识点高级进阶干货需要的可以免费分享给大家,需要的可以加入我的官方群点击此处

ThinkPHP6源码分析之应用初始化的更多相关文章

  1. Spring IOC 容器源码分析 - 余下的初始化工作

    1. 简介 本篇文章是"Spring IOC 容器源码分析"系列文章的最后一篇文章,本篇文章所分析的对象是 initializeBean 方法,该方法用于对已完成属性填充的 bea ...

  2. SDL2源码分析1:初始化(SDL_Init())

    ===================================================== SDL源码分析系列文章列表: SDL2源码分析1:初始化(SDL_Init()) SDL2源 ...

  3. Thinkphp6源码分析之解析,Thinkphp6路由,Thinkphp6路由源码解析,Thinkphp6请求流程解析,Thinkphp6源码

    Thinkphp6源码解析之分析 路由篇-请求流程 0x00 前言: 第一次写这么长的博客,所以可能排版啊,分析啊,什么的可能会比较乱.但是我大致的流程已经觉得是说的够清楚了.几乎是每行源码上都有注释 ...

  4. nginx源码分析之网络初始化

    nginx作为一个高性能的HTTP服务器,网络的处理是其核心,了解网络的初始化有助于加深对nginx网络处理的了解,本文主要通过nginx的源代码来分析其网络初始化. 从配置文件中读取初始化信息 与网 ...

  5. Bootstrap源码分析系列之初始化和依赖项

    在上一节中我们介绍了Bootstrap整体架构,本节我们将介绍Bootstrap框架第二部分初始化及依赖项,这部分内容位于源码的第8~885行,打开源码这部分内容似乎也不是很难理解.但是请站在一个开发 ...

  6. nginx源码分析之模块初始化

    在nginx启动过程中,模块的初始化是整个启动过程中的重要部分,而且了解了模块初始化的过程对应后面具体分析各个模块会有事半功倍的效果.在我看来,分析源码来了解模块的初始化是最直接不过的了,所以下面主要 ...

  7. linux内存源码分析 - 页表的初始化

    本文为原创,转载请注明:http://www.cnblogs.com/tolimit/ 本文章中系统我们假设为x86下的32位系统,暂且不分析64位系统的页表结构. linux分页 linux下采用四 ...

  8. SQLmap源码分析之框架初始化(一)

    SQLmap是现在搞web人手一个的注入神器,不仅包含了主流数据库的SQL注入检测,而且包含提权以及后渗透模块.基于python2.x开发而成,使用方便.所以研究web安全少不了分析源码,学习代码的同 ...

  9. [ethereum源码分析](3) ethereum初始化指令

    前言 在上一章介绍了关于区块链的一些基础知识,这一章会分析指令 geth --datadir dev/data/02 init private-geth/genesis.json 的源码,若你的eth ...

随机推荐

  1. 公有IP和私有IP的区别

    什么是IP? 在网络中,每台计算机都有一个唯一的地址,方便别人找到它,这个地址称为IP地址 IP地址是一个网络编码,用来确定网络中的一个节点,是由32位的二进制组成 IP地址的组成? IP地址由网络部 ...

  2. 能使Oracle索引失效的七大限制条件

    Oracle 索引的目标是避免全表扫描,提高查询效率,但有些时候却适得其反. 例如一张表中有上百万条数据,对某个字段加了索引,但是查询时性能并没有什么提高,这可能是 oracle 索引失效造成的.or ...

  3. python lib timeit 测试运行时间

    目录 1. 简介 1.1. python interface 2. 案例 2.1. timeit() /repeat() 2.2. timer() 1. 简介 27.5. timeit - Measu ...

  4. c++调用自己编写的静态库(通过eclipse)

    转:https://blog.csdn.net/hao5335156/article/details/80282829 参考:https://blog.csdn.net/u012707739/arti ...

  5. FromBase64String 输入的不是有效的 Base-64 字符串,因为它包含非 Base-64 字符、两个以上的填充字符,或者填充字符间包含非法字符

    js前台: <input id="upload_img_input" v-on:change="onFileChange" type="file ...

  6. springBoot日志快速上手简单配置

    默认配置 日志级别从低到高分为: TRACE < DEBUG < INFO < WARN < ERROR < FATAL. 如果设置为 INFO ,则低于 INFO 的信 ...

  7. 对DensePose: Dense Human Pose Estimation In The Wild的理解

    研究方法 通过完全卷积学习从图像像素到密集模板网格的映射.将此任务作为一个回归问题,并利用手动注释的面部标注来训练我们的网络.使用这样的标注,在三维对象模板和输入图像之间,建立密集的对应领域,然后作为 ...

  8. Ip2Region IP转化地址位置

    Ip2Region有中文和数据结构支持,是一个很好的第三方ip转换工具. java: <dependency> <groupId>org.lionsoul</groupI ...

  9. 吴裕雄 PYTHON 神经网络——TENSORFLOW 单隐藏层自编码器设计处理MNIST手写数字数据集并使用TensorBord描绘神经网络数据

    import os import numpy as np import tensorflow as tf import matplotlib.pyplot as plt from tensorflow ...

  10. Spring Bean 有关的那些注解

    尊重原著直接贴链接 https://mp.weixin.qq.com/s/7lhpEo73KG3-xPgbFiaLHw