Request许多框架将客户端的请求抽象成类,方便应用程序使用,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__.'/../引导程序/app.php';$kernel=$app->make(Illuminate\Contracts\Http\Kernel::class);$response=$kernel->handle(//创建请求对象$request=Illuminate\Http\Request::capture());客户端的HTTP请求是Illuminate\Http\Request类的一个对象classRequestextendsSymfonyRequestimplementsArrayable,ArrayAccess{//创建一个新的Request实例返回静态::createFromBase(SymfonyRequest::createFromGlobals());}}通过Illuminate\Http\Request类的源码我们可以看出它继承自Symfony的Request类,所以Illuminate\Http\Request类中实现的很多功能都是基于Symfony提供的功能实现的要求。从上面的代码可以看出,在新建Request对象时,捕获方法也依赖于SymfonyRequest类的实例。namespaceSymfony\Component\HttpFoundation;classRequest{/***根据PHP提供的超级全局数据组来创建SmyfonyRequest实例**@returnstatic*/publicstaticfunctioncreateFromGlobals(){//随着php的错误#66606,php的内置Web服务器//将Content-Type和Content-Length标头值存储在//HTTP_CONTENT_TYPE和HTTP_CONTENT_LENGTH字段中。$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);如果(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=newParameterBag($data);}返回$请求;上面的代码有一部分需要解释一下,从PHP5.4开始,PHP内置内置的web服务器可以通过命令行解释器启动,例如:php-Slocalhost:8000-thtdocs-S:使用内置网络服务器运行。-t为内置网络服务器指定文档根目录。但是,内置的Web服务器有一个错误,即在HTTP_CONTENT_LENGTH和HTTP_CONTENT_TYPE中存储了两个请求标头CONTENT_LENGTH和CONTENT_TYPE。为了统一内置服务器和真实服务器中的请求头字段,这里特殊处理SymfonyRequest实例是通过PHP中的超级全局数组创建的。这些超级全局数组包括$_GET、$_POST、$_COOKIE、$_FILES、$_SERVER,涵盖了PHP中所有与HTTP请求相关的超级全局数组。在创建SymfonyRequest实例时,将基于这些全局数组创建SymfonyPackage中提供的ParamterBagServerBagFileBagHeaderBag实例。这些Bags是Symfony提供的不同HTTP组件的访问和设置API。对Symfony提供的这些ParamterBag实例感兴趣的读者可以自己去源码看看,这里就不多说了。classRequest{/***@paramarray$queryGET参数*@paramarray$requestPOST参数*@paramarray$attributes请求属性(从PATH_INFO解析的参数,...)*@paramarray$cookiesCOOKIE参数*@paramarray$filesFILES参数*@paramarray$serverSERVER参数*@paramstring|resource|null$content原始数据*/publicfunction__construct(array$query=array(),array$request=array(),array$attributes=array(),array$cookies=array(),array$files=array(),array$server=array(),$content=null){$this->初始化($query,$request,$attributes,$cookies,$files,$server,$content);}公共函数初始化(数组$query=数组(),数组$request=数组(),数组$attributes=数组(),数组$cookies=array(),数组$files=array(),数组$server=array(),$content=null){$this->request=newParameterBag($request);$this->query=newParameterBag($query);$this->attributes=newParameterBag($attributes);$this->cookies=newParameterBag($cookies);$this->files=newFileBag($files);$this->server=newServerBag($server);$this->headers=newHeaderBag($this->server->getHeaders());$this->content=$content;$this->languages=null;$this->charsets=null;$this->编码=空;$this->acceptableContentTypes=null;$this->pathInfo=null;$this->requestUri=null;$this->baseUrl=null;$this->basePath=null;$this->method=null;$this->format=null;可以看到SymfonyRequest类除了上面提到的还有很多属性,这些属性共同构成了对HTTP请求的完整抽象,我们可以通过实例属性方便访问Method、Charset等HTTP请求的属性在获取到SymfonyRequest实例后,Laravel会克隆该实例并重置它的一些属性:$request){if($requestinstanceofstatic){返回$request;$content=$request->content;$request=(newstatic)->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();返回$请求;}publicfunctionduplicate(array$query=null,array$request=null,array$attributes=null,array$cookies=null,array$files=null,array$server=null){returnparent::duplicate($query,$请求,$在贡品,$cookies,$this->filterFiles($files),$server);}}//SymfonyRequest中的重复方法publicfunctionduplicate(array$query=null,array$request=null,array$attributes=null,array$cookies=null,array$files=null,array$server=null){$dup=克隆$this;if(null!==$query){$dup->query=newParameterBag($query);}if(null!==$request){$dup->request=newParameterBag($request);}if(null!==$attributes){$dup->attributes=newParameterBag($attributes);}if(null!==$cookies){$dup->cookies=newParameterBag($cookies);}if(null!==$files){$dup->files=newFileBag($files);}if(null!==$server){$dup->server=newServerBag($server);$dup->headers=newHeaderBag($dup->server->getHeaders());}$dup->语言=null;$dup->charsets=null;$dup->编码=空;$dup->acceptableContentTypes=null;$dup->pathInfo=null;$dup->requestUri=null;$dup->baseUrl=null;$dup->basePath=null;$dup->方法=空;$dup->格式=空;如果(!$dup->get('_format')&&$this->get('_format')){$dup->attributes->set('_format',$this->get('_format'));}if(!$dup->getRequestFormat(null)){$dup->setRequestFormat($this->getRequestFormat(null));}返回$dup;创建Request对象后,我们可以很容易地在Laravel应用程序中应用它提供的功能。如果你在使用Request对象的时候不知道是否实现了你想要的功能,去Illuminate\Http\Request的源代码文件中查看一下就很简单了。此源代码文件中列出了所有方法,例如:/***获取请求的完整URL。*获取请求的URL(包括host,不包括查询字符串)**@returnstring*/publicfunctionfullUrl(){$query=$this->getQueryString();$任务ion=$this->getBaseUrl().$this->getPathInfo()=='/'?“/?”:'?';返回$查询?$this->url().$question.$query:$this->url();}/***使用添加的查询字符串参数获取请求的完整URL。*获取包含查询字符串的完整URL**@paramarray$query*@returnstring*/publicfunctionfullUrlWithQuery(array$query){$question=$this->getBaseUrl().$this->getPathInfo()=='/'?“/?”:'?';返回计数($this->query())>0?$this->url().$question.http_build_query(array_merge($this->query(),$query)):$this->fullUrl().$question.http_build_query($query);}请求经过的站创建请求对象后,Laravel的HttpKernel会继续执行:加载服务提供者引导Laravel应用,启动应用,让请求经过基础中间件,找到路由通过router匹配对应到request,并执行匹配到的路由和Request通过路由到中间件到达controller方法。总结随着Request最终到达对应的controller方法,它的使命就基本完成了。在controller方法中,从Request中获取入参,然后Execute应用程序的某个业务逻辑得到一个result,这个result会转换成一个Response响应对象返回给请求的client。这篇文章主要梳理一下Laravel中的Request对象,主要是让大家知道如何去了解Laravel中Request目前提供了哪些能力供我们使用,避免在业务代码中重新造轮子去实现Request已经提供的方法。本文已收录在Laravel源码学习系列文章中,欢迎访问阅读。