>  기사  >  백엔드 개발  >  요청의 Laravel 핵심 해석

요청의 Laravel 핵심 해석

不言
不言원래의
2018-07-06 14:54:374051검색

이 기사에서는 Laravel에서 특정 참조 가치가 있는 Request의 핵심 해석을 주로 소개합니다. 이제 모든 사람과 공유합니다. 도움이 필요한 친구들이 참조할 수 있습니다.

Request

많은 프레임워크에서는 편의를 위해 클라이언트의 요청을 클래스로 추상화합니다. 애플리케이션 사용은 Laravel에서도 예외는 아닙니다. IlluminateHttpRequest 클래스는 Laravel 프레임워크의 클라이언트 요청을 추상화한 것입니다. 이는 Symfony 프레임워크에서 제공하는 Request 구성 요소를 기반으로 구축되었습니다. 오늘 글에서는 라라벨이 Request 객체를 생성하는 방법을 간략하게 살펴보겠습니다. Request 객체가 애플리케이션에 제공하는 기능에 대해서는 너무 자세히 설명하지 않겠습니다. 생성 과정에 대한 설명을 마친 후에는 어디로 가야 할지 알게 될 것입니다. Request 객체에서 제공하는 메소드를 찾아보세요. 일부 온라인 치트 시트에는 Request에서 제공하는 일부 메소드가 나열되어 있지만 일부는 완전하지 않고 설명도 되어 있지 않습니다. Request는 개발 중에 원하는 기능을 달성했습니다. Request의 소스 코드로 이동하여 해당 메서드가 있는지 확인하세요. 각 메서드의 실행 결과는 메서드 주석에 명확하게 표시되어 있습니다. 요점을 살펴 보겠습니다. IlluminateHttpRequest类在Laravel框架中就是对客户端请求的抽象,它是构建在Symfony框架提供的Request组件基础之上的。今天这篇文章就简单来看看Laravel是怎么创建请求Request对象的,而关于Request对象为应用提供的能力我并不会过多去说,在我讲完创建过程后你也就知道去源码哪里找Request对象提供的方法了,网上有些速查表列举了一些Request提供的方法不过不够全并且有的也没有解释,所以我还是推荐在开发中如果好奇Request是否已经实现了你想要的能力时去Request的源码里看下有没有提供对应的方法,方法注释里都清楚地标明了每个方法的执行结果。下面让我们进入正题吧。

创建Request对象

我们可以在Laravel应用程序的index.php文件中看到,在Laravel应用程序正式启动完成前Request对象就已经被创建好了:

//public/index.php
$app = require_once __DIR__.'/../bootstrap/app.php';

$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);

$response = $kernel->handle(
    //创建request对象
    $request = Illuminate\Http\Request::capture()
);

客户端的HTTP请求是IlluminateHttpRequest类的对象

class Request extends SymfonyRequest implements Arrayable, ArrayAccess
{
    //新建Request实例
    public static function capture()
    {
        static::enableHttpMethodParameterOverride();

        return static::createFromBase(SymfonyRequest::createFromGlobals());
    }
}

通过IlluminateHttpRequest类的源码可以看到它是继承自Symfony Request类的,所以IlluminateHttpRequest类中实现的很多功能都是以Symfony Reques提供的功能为基础来实现的。上面的代码就可以看到capture方法新建Request对象时也是依赖于Symfony Request类的实例的。

namespace Symfony\Component\HttpFoundation;
class Request
{
    /**
     * 根据PHP提供的超级全局数组来创建Smyfony Request实例
     *
     * @return static
     */
    public static function createFromGlobals()
    {
        // With the php's bug #66606, the php's built-in web server
        // stores the Content-Type and Content-Length header values in
        // HTTP_CONTENT_TYPE and HTTP_CONTENT_LENGTH fields.
        $server = $_SERVER;
        if ('cli-server' === PHP_SAPI) {
            if (array_key_exists('HTTP_CONTENT_LENGTH', $_SERVER)) {
                $server['CONTENT_LENGTH'] = $_SERVER['HTTP_CONTENT_LENGTH'];
            }
            if (array_key_exists('HTTP_CONTENT_TYPE', $_SERVER)) {
                $server['CONTENT_TYPE'] = $_SERVER['HTTP_CONTENT_TYPE'];
            }
        }

        $request = self::createRequestFromFactory($_GET, $_POST, array(), $_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')), array('PUT', 'DELETE', 'PATCH'))
        ) {
            parse_str($request->getContent(), $data);
            $request->request = new ParameterBag($data);
        }

        return $request;
    }
    
}

上面的代码有一处需要额外解释一下,自PHP5.4开始PHP内建的builtin web server可以通过命令行解释器来启动,例如:

php -S localhost:8000 -t htdocs

-S 9581b3ba3b9ee3c707d01b5722440004:298c9bd6ad6e8c821dc63aa0473d6209 Run with built-in web server.
-t ea23c61ebf6b70b26359136364366495     Specify document root ea23c61ebf6b70b26359136364366495 for built-in web server.

但是内建web server有一个bug是将CONTENT_LENGTHCONTENT_TYPE这两个请求首部存储到了HTTP_CONTENT_LENGTHHTTP_CONTENT_TYPE中,为了统一内建服务器和真正的server中的请求首部字段所以在这里做了特殊处理。

Symfony Request 实例的创建是通过PHP中的超级全局数组来创建的,这些超级全局数组有$_GET$_POST$_COOKIE$_FILES$_SERVER涵盖了PHP中所有与HTTP请求相关的超级全局数组,创建Symfony Request实例时会根据这些全局数组创建Symfony Package里提供的ParamterBag ServerBag FileBag HeaderBag实例,这些Bag都是Symfony提供地针对不同HTTP组成部分的访问和设置API, 关于Symfony提供的ParamterBag这些实例有兴趣的读者自己去源码里看看吧,这里就不多说了。

class Request
{

    /**
     * @param array                $query      The GET parameters
     * @param array                $request    The POST parameters
     * @param array                $attributes The request attributes (parameters parsed from the PATH_INFO, ...)
     * @param array                $cookies    The COOKIE parameters
     * @param array                $files      The FILES parameters
     * @param array                $server     The SERVER parameters
     * @param string|resource|null $content    The raw body data
     */
    public function __construct(array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null)
    {
        $this->initialize($query, $request, $attributes, $cookies, $files, $server, $content);
    }
    
    public function initialize(array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null)
    {
        $this->request = new ParameterBag($request);
        $this->query = new ParameterBag($query);
        $this->attributes = new ParameterBag($attributes);
        $this->cookies = new ParameterBag($cookies);
        $this->files = new FileBag($files);
        $this->server = new ServerBag($server);
        $this->headers = new HeaderBag($this->server->getHeaders());

        $this->content = $content;
        $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;
    }
    
}

可以看到Symfony Request类除了上边说到的那几个,还有很多属性,这些属性在一起构成了对HTTP请求完整的抽象,我们可以通过实例属性方便地访问MethodCharset等这些HTTP请求的属性。

拿到Symfony Request实例后, Laravel会克隆这个实例并重设其中的一些属性:

namespace Illuminate\Http;
class Request extends ....
{
    //在Symfony request instance的基础上创建Request实例
    public static function createFromBase(SymfonyRequest $request)
    {
        if ($request instanceof static) {
            return $request;
        }

        $content = $request->content;

        $request = (new static)->duplicate(
            $request->query->all(), $request->request->all(), $request->attributes->all(),
            $request->cookies->all(), $request->files->all(), $request->server->all()
        );

        $request->content = $content;

        $request->request = $request->getInputSource();

        return $request;
    }
    
    public function duplicate(array $query = null, array $request = null, array $attributes = null, array $cookies = null, array $files = null, array $server = null)
    {
        return parent::duplicate($query, $request, $attributes, $cookies, $this->filterFiles($files), $server);
    }
}
    //Symfony Request中的 duplicate方法
    public function duplicate(array $query = null, array $request = null, array $attributes = null, array $cookies = null, array $files = null, array $server = null)
    {
        $dup = clone $this;
        if (null !== $query) {
            $dup->query = new ParameterBag($query);
        }
        if (null !== $request) {
            $dup->request = new ParameterBag($request);
        }
        if (null !== $attributes) {
            $dup->attributes = new ParameterBag($attributes);
        }
        if (null !== $cookies) {
            $dup->cookies = new ParameterBag($cookies);
        }
        if (null !== $files) {
            $dup->files = new FileBag($files);
        }
        if (null !== $server) {
            $dup->server = new ServerBag($server);
            $dup->headers = new HeaderBag($dup->server->getHeaders());
        }
        $dup->languages = null;
        $dup->charsets = null;
        $dup->encodings = null;
        $dup->acceptableContentTypes = null;
        $dup->pathInfo = null;
        $dup->requestUri = null;
        $dup->baseUrl = null;
        $dup->basePath = null;
        $dup->method = null;
        $dup->format = null;

        if (!$dup->get('_format') && $this->get('_format')) {
            $dup->attributes->set('_format', $this->get('_format'));
        }

        if (!$dup->getRequestFormat(null)) {
            $dup->setRequestFormat($this->getRequestFormat(null));
        }

        return $dup;
    }

Request对象创建好后在Laravel应用中我们就能方便的应用它提供的能力了,在使用Request对象时如果你不知道它是否实现了你想要的功能,很简单直接去IlluminateHttpRequest

요청 객체 생성

Laravel 애플리케이션이 공식적으로 시작되기 전에 요청 객체가 생성되었음을 Laravel 애플리케이션의 index.php 파일에서 확인할 수 있습니다.

/**
 * Get the full URL for the request.
 * 获取请求的URL(包含host, 不包括query string)
 *
 * @return string
 */
public function fullUrl()
{
    $query = $this->getQueryString();

    $question = $this->getBaseUrl().$this->getPathInfo() == '/' ? '/?' : '?';

    return $query ? $this->url().$question.$query : $this->url();
}

/**
 * Get the full URL for the request with the added query string parameters.
 * 获取包括了query string 的完整URL
 *
 * @param  array  $query
 * @return string
 */
public function fullUrlWithQuery(array $query)
{
    $question = $this->getBaseUrl().$this->getPathInfo() == '/' ? '/?' : '?';

    return count($this->query()) > 0
        ? $this->url().$question.http_build_query(array_merge($this->query(), $query))
        : $this->fullUrl().$question.http_build_query($query);
}

Customer HTTP 요청 클라이언트에는 IlluminateHttpRequest 클래스의 객체가 있습니다

rrreee

Symfony Request에서 상속받은 IlluminateHttpRequest 클래스의 소스 코드에서 볼 수 있습니다. code> 클래스이므로 IlluminateHttpRequest 클래스에 구현된 많은 함수는 Symfony Reques에서 제공하는 함수를 기반으로 합니다. 위 코드에서 capture 메소드가 새 Request 객체를 생성할 때 Symfony Request 클래스의 인스턴스에도 의존한다는 것을 알 수 있습니다.

rrreee

위 코드에는 추가 설명이 필요한 부분이 있습니다. PHP5.4부터 PHP의 내장 웹 서버는 명령줄 인터프리터를 통해 시작할 수 있습니다. 예:

php -S localhost:8000 - t htdocs

rrreee

하지만 내장 웹 서버에는 두 개의 요청 헤더 CONTENT_LENGTHCONTENT_TYPEHTTP_CONTENT_LENGTH에 저장하는 버그가 있습니다. > 및 HTTP_CONTENT_TYPE에서는 내장 서버와 실제 서버의 요청 헤더 필드를 통합하기 위해 여기에서 특수 처리가 수행됩니다.

Symfony 요청 인스턴스는 PHP의 슈퍼 전역 배열을 통해 생성됩니다. 이러한 슈퍼 전역 배열에는 $_GET, $_POST, $_COOKIE, $_FILES, $_SERVER는 PHP의 HTTP 요청과 관련된 모든 슈퍼 전역 배열을 포함합니다. Symfony 패키지는 Symfony 요청 인스턴스를 생성할 때 이러한 전역 배열을 기반으로 생성됩니다. ParamterBag ServerBag FileBag HeaderBag는 Access 및 Set API에서 제공됩니다. ParamterBag의 예에 관심이 있는 독자입니다. code>는 Symfony에서 제공하는 소스 코드를 직접 확인할 수 있습니다. 여기서는 자세히 설명하지 않겠습니다. <p class="mt20 ad-detail-mm hidden-xs">rrreee<a title="Laravel核心解读Facades" href="http://www.php.cn/php-weizijiaocheng-406082.html" target="_blank">Symfony Request 클래스에는 위에서 언급한 속성 외에도 많은 속성이 포함되어 있어 HTTP 요청의 완전한 추상화를 구성하는 것을 볼 수 있습니다. 인스턴스 속성을 통해 <code>Method에 쉽게 액세스할 수 있습니다. <code>문자 집합 및 이러한 HTTP 요청의 기타 속성입니다.
Symfony Request 인스턴스를 얻은 후 Laravel은 인스턴스를 복제하고 일부 속성을 재설정합니다.

rrreee🎜Request 객체가 생성된 후 Request 객체 If를 사용할 때 Laravel 애플리케이션에서 제공하는 기능을 쉽게 적용할 수 있습니다. 원하는 기능이 구현되었는지 알 수 없다면 IlluminateHttpRequest의 소스 코드 파일로 직접 이동하여 확인하는 것이 쉽습니다. 예를 들면 다음과 같습니다. 🎜 rrreee 🎜Request가 통과하는 스테이션🎜🎜Request 객체를 생성한 후에도 Laravel의 Http Kernel은 계속해서 실행됩니다. Laravel 애플리케이션을 안내하는 서비스 제공자를 로드하고, 애플리케이션을 시작하고, 요청이 기본 미들웨어를 통과하도록 하고, Router 매칭을 통해 Request에 해당하는 경로를 찾고, 매칭된 경로를 실행하며, Request는 미들웨어 경로를 통해 컨트롤러 메소드에 도달합니다. 🎜🎜Summary🎜🎜Request가 해당 컨트롤러 메소드에 도달하면 기본적으로 임무가 완료됩니다. 컨트롤러 메소드에서는 Request에서 입력 매개변수를 얻은 다음 애플리케이션의 특정 비즈니스 로직을 실행하여 결과를 얻습니다. 결과는 다음과 같습니다. 응답 개체로 변환되어 요청을 시작한 클라이언트에 반환됩니다. 🎜🎜이 글은 주로 Laravel의 Request 객체를 분류하여 메소드를 구현하기 위해 비즈니스 코드를 다시 만드는 것을 피하기 위해 Laravel의 Request가 현재 우리에게 제공하는 기능이 무엇인지 알아내는 방법을 모든 사람이 알기를 바랍니다. 요청에 의해 이미 제공되었습니다. 🎜🎜위 내용은 이 글의 전체 내용입니다. 모든 분들의 학습에 도움이 되었으면 좋겠습니다. 더 많은 관련 내용은 PHP 중국어 홈페이지를 주목해주세요! 🎜🎜관련 권장 사항: 🎜🎜🎜Laravel Core Interpretation Facades🎜🎜🎜

위 내용은 요청의 Laravel 핵심 해석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.