【Laravel-海贼王系列】第五章,Request 类解析

613 阅读2分钟

分解laravel的请求类,看看如何解析Http请求。

头部声明

namespace Illuminate\Http;

use Closure;
use ArrayAccess; // "支持数组和对象互相调用语法兼容接口"
use RuntimeException;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Illuminate\Support\Traits\Macroable; // "引入这个特质方便拓展类"
use Illuminate\Contracts\Support\Arrayable; // "需要类支持toArray()方法的契约"
use Symfony\Component\HttpFoundation\ParameterBag;
use Symfony\Component\HttpFoundation\Request as SymfonyRequest;

// "laravel的请求类继承了Symfony的的请求对象,同时需要支持toArray()契约和数组对象互相调用语法支持接口"
class Request extends SymfonyRequest implements Arrayable, ArrayAccess
{
    use Concerns\InteractsWithContentTypes,
        Concerns\InteractsWithFlashData,
        Concerns\InteractsWithInput,
        Macroable;
} 

核心方法

• 获取请求对象

public static function capture() 
{
    // "这行指启动方法重载,能够在前端通过 {{method_field('PUT')}} 伪造一个 PUT 或者 DELETE 请求。"
    static::enableHttpMethodParameterOverride();

    // "这行就是laravel怎么捕获整个请求中数据的关键,我们来展开分解。"
    return static::createFromBase(SymfonyRequest::createFromGlobals());
}

• 先看看如何生成一个SymfonyRequest请求对象的

public static function createFromGlobals() 
{
    // 通过传入这些参数获取SymfonyRequest的实例化对象
    $request = self::createRequestFromFactory($_GET, $_POST, [], $_COOKIE, $_FILES, $_SERVER); 

    if (0 === strpos($request->headers->get('CONTENT_TYPE'), 'application/x-www-form-urlencoded')
        && \in_array(strtoupper($request->server->get('REQUEST_METHOD', 'GET')), ['PUT', 'DELETE', 'PATCH'])
    ) {
        // "解析数据,如果是PUT,DELETE,PATCH这集中方法以及头部是x-www-form-urlencoded则需要根据
            数据类型是二进制,资源,流等来进行读取并且赋值到数组$data"
        parse_str($request->getContent(), $data);
        
        // "new一个ParameterBag实例传给$request对象的request属性"
        $request->request = new ParameterBag($data); 
    }

    return $request;
}
    
// "上面的self::createRequestFromFactory($_GET, $_POST, [], $_COOKIE, $_FILES,

$_SERVER)是调用SymfonyRequest初始化方法,只不过是将PHP超全局数组赋值给对象的对应成员。"

public function initialize(array $query = [], array $request = [], array $attributes = [], array $cookies = [], array $files = [], array $server = [], $content = null)
{
    $this->request = new ParameterBag($request); // $_POST
    $this->query = new ParameterBag($query); // $_GET
    $this->attributes = new ParameterBag($attributes); // []
    $this->cookies = new ParameterBag($cookies); // $_COOKIE
    $this->files = new FileBag($files); // $_FILES
    $this->server = new ServerBag($server); // $_SERVER
    $this->headers = new HeaderBag($this->server->getHeaders())

    $this->content = $content; // null
    $this->languages = null;
    $this->charsets = null;
    $this->encodings = null;
    $this->acceptableContentTypes = null;
    $this->pathInfo = null;
    $this->requestUri = null;
    $this->baseUrl = null;
    $this->basePath = null;
    $this->method = null;
    $this->format = null;
}
    
 • 最后看如何根据SymfonyRequest请求实例来生成laravel的Request实例
 
public static function createFromBase(SymfonyRequest $request)
{
    // "如果传入的$request是Illuminate\Http\Request对象则直接返回。"
    if ($request instanceof static) {
        return $request;
    }

    // "读取request中的内容"
    $content = $request->content;

    // "克隆一个新的对象将SymfonyRequest中的参数覆盖其中的部分参数。"
    $request = (new static)->duplicate(
        $request->query->all(), $request->request->all(), $request->attributes->all(),
        $request->cookies->all(), $request->files->all(), $request->server->all()
    );

    // "重新赋值给Illuminate\Http\Request对象。"
    $request->content = $content;

    // "获取请求中的数据"
    $request->request = $request->getInputSource();

    // "返回Illuminate\Http\Request对象"
    return $request;
}

总结

laravel中的请求是在SymfonyRequest的基础进行继承,

同时增加了自己的一些方法进去。

最终在框架中直接使用的是Illuminate\Http\Request对象。

当然请求类里面还有很多其他附带的方法,

但是目前只分析在框架启动过程中请求对象

是如何发挥作用的。