很多框架都會將來自客戶端的請求抽象成類方便html' target='_blank'>應用程序使用,在Laravel中也不例外。Illuminate/Http/Request類在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請求是Illuminate/Http/Request類的對象
class Request extends SymfonyRequest implements Arrayable, ArrayAccess //新建Request實例 public static function capture() static::enableHttpMethodParameterOverride(); return static::createFromBase(SymfonyRequest::createFromGlobals());}
通過Illuminate/Http/Request類的源碼可以看到它是繼承自Symfony Request類的,所以Illuminate/Http/Request類中實現的很多功能都是以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對象時如果你不知道它是否實現了你想要的功能,很簡單直接去Illuminate/Http/Request的源碼文件里查看就好了,所有方法都列在了這個源碼文件里,比如:
/** * Get the full URL for the request. * 獲取請求的URL(包含host, 不包括query string) * @return stringpublic 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 stringpublic 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);}Request經過的驛站
創建完Request對象后, Laravel的Http Kernel會接著往下執行:加載服務提供器引導Laravel應用、啟動應用、讓Request經過基礎的中間件、通過Router匹配查找Request對應的路由、執行匹配到的路由、Request經過路由上到中間件到達控制器方法。
總結隨著Request最終到達對應的控制器方法后它的使命基本上也就完成了, 在控制器方法里從Request中獲取輸入參數然后執行應用的某一業務邏輯獲得結果,結果會被轉化成Response響應對象返回給發起請求的客戶端。
這篇文章主要梳理了Laravel中Request對象,主要是想讓大家知道如何去查找Laravel中Request現有提供了哪些能力供我們使用避免我們在業務代碼里重新造輪子去實現Request已經提供的方法。
以上就是本文的全部內容,希望對大家的學習有所幫助,更多相關內容請關注PHP !
相關推薦:
Laravel核心解讀Facades
Laravel中間件(Middleware)的解讀
以上就是Laravel核心解讀Request的詳細內容,PHP教程
鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯系我們修改或刪除,多謝。
新聞熱點
疑難解答