ThinkPHP6 源码分析之解析 Request

获取 Request 对像

在进入正题之前,需要重点说一下 make 方法。因为从上个版本使用过来的人已经开始接受 Container 这个概念了,这个新版本的增强了 Container 的功能,创建 Request 对象的精髓就在 make 方法。倒不如说整个框架核心类都在使用这个方法。我们来看一下这个方法是如何创建对象的。具体说明请看每一段的注释

public function make(string $abstract, array $vars = [], bool $newInstance = false)
{
    // 首先说明 instances 属性是一个数组,就是主要存储容器对象
    // 如果对象存在与容器中并且不需要重新创建的话,就直接从容器中获取
    if (isset($this->instances[$abstract]) && !$newInstance) {
        return $this->instances[$abstract];
    }
    // bind 属性从上一个应用初始化已经接触到了,
    // 就是容器对象的绑定标识,和 instances 数组不同的是,
   // 它只是存储了一个类字符串而已,需要实例化后获取对象实例,下面就是实现的该功能

    // 如果 bind 标识存在
    if (isset($this->bind[$abstract])) {
        // 从 bind 获取
        $concrete = $this->bind[$abstract];
        // concrete 可能是一个类名或者是一个匿名函数
        // 匿名函数直接执行
        if ($concrete instanceof Closure) {
            $object = $this->invokeFunction($concrete, $vars);
        } else {
            // 否则继续 make 创建,因为此时还没创建出对象
            return $this->make($concrete, $vars, $newInstance);
        }
    } else {
        // 如果没有在标识中 说明需要的类名真正的产出了,需要实例化。
        // 其实这里才是真正的创建类,并且下面的方法直接依赖注入
        $object = $this->invokeClass($abstract, $vars);
    }
    // 对于不需要创建实例的类 直接放在容器中管理
    if (!$newInstance) {
        $this->instances[$abstract] = $object;
    }
    // 最后返回对象
    return $object;
}

可能到这里看的还是有点糊涂,正好在这里用 Request 创建来梳理一下。我们来看看创建 Request 的过程。

分析

下面这段代码可以的 run 方法中找到,这段代码需要仔细推敲,不然你无法知道这个 Request 对象到底是哪个?

//自动创建request对象
$request = $request ?? $this->app->make('request', [], true);
$this->app->instance('request', $request);

$newInstance 在 Request 创建时被设置为了 true,说明每次请求都需要重新创建。此时 instances 还未有 Request 对象,所以继续忽略。
在进入 bind 之前,先看看 bind 里面都有什么了?

array(22) {
  ["app"]=>
  string(9) "think\App"
  ["cache"]=>
  string(11) "think\Cache"
  ["config"]=>
  string(12) "think\Config"
  ["console"]=>
  string(13) "think\Console"
  ["cookie"]=>
  string(12) "think\Cookie"
  ["db"]=>
  string(8) "think\Db"
  ["env"]=>
  string(9) "think\Env"
  ["event"]=>
  string(11) "think\Event"
  ["http"]=>
  string(10) "think\Http"
  ["lang"]=>
  string(10) "think\Lang"
  ["log"]=>
  string(9) "think\Log"
  ["middleware"]=>
  string(16) "think\Middleware"
  ["request"]=>
  string(13) "think\Request"
  ["response"]=>
  string(14) "think\Response"
  ["route"]=>
  string(11) "think\Route"
  ["session"]=>
  string(13) "think\Session"
  ["validate"]=>
  string(14) "think\Validate"
  ["view"]=>
  string(10) "think\View"
  ["filesystem"]=>
  string(16) "think\Filesystem"
  ["Psr\Log\LoggerInterface"]=>
  string(9) "think\Log"
  ["think\Request"]=>
  string(11) "app\Request"
  ["think\exception\Handle"]=>
  string(19) "app\ExceptionHandle"
}

默认已经有了很多类名,这些都是框架默认的,不需要管,我们只看 request 键名和 ‘think\Request‘,还有最后两个 think\Requestthink\exception\Handle
是在框架初始化注入进来的,不清楚的可以看上一节。think\Request 就是在那个时候注入的。

下面进入正题,很明显 'request' 在存在与 bind 中的,并且 request 的值并不是一个匿名函数,而是一个字符串 think\Request,只能继续 make 创建,找到 think\Request对应的值 app\Request,它并不存在与 bind 中,所以直接来解析这个类名。这里大概就明白了,实际框架并没有在使用 think\Request 对象,而是 app\Request 对象。在解析后,Request 对象也被放进了容器了。下面就是请求的执行过程了。

原文转载于 ThinkPHP6 源码分析之解析 Request

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 1
VeryCool

我都还在5 你们都开始研究6了

4年前 评论
JaguarJack (楼主) 4年前
shenghuo1991 4年前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!