이 기사에서는 Laravel에서 특정 참조 가치가 있는 Request의 핵심 해석을 주로 소개합니다. 이제 모든 사람과 공유합니다. 도움이 필요한 친구들이 참조할 수 있습니다.
많은 프레임워크에서는 편의를 위해 클라이언트의 요청을 클래스로 추상화합니다. 애플리케이션 사용은 Laravel에서도 예외는 아닙니다. IlluminateHttpRequest
클래스는 Laravel 프레임워크의 클라이언트 요청을 추상화한 것입니다. 이는 Symfony
프레임워크에서 제공하는 Request 구성 요소를 기반으로 구축되었습니다. 오늘 글에서는 라라벨이 Request 객체를 생성하는 방법을 간략하게 살펴보겠습니다. Request 객체가 애플리케이션에 제공하는 기능에 대해서는 너무 자세히 설명하지 않겠습니다. 생성 과정에 대한 설명을 마친 후에는 어디로 가야 할지 알게 될 것입니다. Request 객체에서 제공하는 메소드를 찾아보세요. 일부 온라인 치트 시트에는 Request에서 제공하는 일부 메소드가 나열되어 있지만 일부는 완전하지 않고 설명도 되어 있지 않습니다. Request는 개발 중에 원하는 기능을 달성했습니다. Request의 소스 코드로 이동하여 해당 메서드가 있는지 확인하세요. 각 메서드의 실행 결과는 메서드 주석에 명확하게 표시되어 있습니다. 요점을 살펴 보겠습니다. IlluminateHttpRequest
类在Laravel框架中就是对客户端请求的抽象,它是构建在Symfony
框架提供的Request组件基础之上的。今天这篇文章就简单来看看Laravel是怎么创建请求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 <addr>:<port> Run with built-in web server. -t <docroot> Specify document root <docroot> for built-in web server.로그인 후 복사
但是内建web server有一个bug是将CONTENT_LENGTH
和CONTENT_TYPE
这两个请求首部存储到了HTTP_CONTENT_LENGTH
和HTTP_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请求完整的抽象,我们可以通过实例属性方便地访问Method
,Charset
等这些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
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); }
IlluminateHttpRequest
클래스의 객체가 있습니다Symfony Request
에서 상속받은 IlluminateHttpRequest
클래스의 소스 코드에서 볼 수 있습니다. code> 클래스이므로 IlluminateHttpRequest
클래스에 구현된 많은 함수는 Symfony Reques
에서 제공하는 함수를 기반으로 합니다. 위 코드에서 capture
메소드가 새 Request 객체를 생성할 때 Symfony Request
클래스의 인스턴스에도 의존한다는 것을 알 수 있습니다. rrreee
위 코드에는 추가 설명이 필요한 부분이 있습니다. PHP5.4부터 PHP의 내장 웹 서버는 명령줄 인터프리터를 통해 시작할 수 있습니다. 예:php -S localhost:8000 - t htdocs하지만 내장 웹 서버에는 두 개의 요청 헤더rrreee
CONTENT_LENGTH
및 CONTENT_TYPE
를 HTTP_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 요청의 기타 속성입니다. 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 중국어 웹사이트의 기타 관련 기사를 참조하세요!