$response = $kernel->handle( $request = Illuminate\Http\Request::capture() );
$request = Illuminate\Http\Request::capture() \Illuminate\Http\Request extends \Symfony\Component\HttpFoundation\Request public static function capture() { static::enableHttpMethodParameterOverride(); return static::createFromBase(SymfonyRequest::createFromGlobals()); } public static function enableHttpMethodParameterOverride() { self::$httpMethodParameterOverride = true; } public static function createFromGlobals() { $server = $_SERVER; // CLI mode 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']; } } // 建立并返回\Symfony\Component\HttpFoundation\Request对象,其实是用全局变量来实例化对应的类(能够对全局变量进行安全过滤),在赋予Request对象 $request = self::createRequestFromFactory($_GET, $_POST, array(), $_COOKIE, $_FILES, $server); // 若是是以PUT|DELETE|PATCH方法进行的标准编码传输方式,就从原始数据的只读流解析数据到request属性(此属性其实对应的是POST键值对,PUT|DELETE|PATCH传输方式会被转成POST方式进行统一处理) 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; } private static function createRequestFromFactory(array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null) { // 若是存在自定义的方法,则调用并返回相应的对象 if (self::$requestFactory) { // 此方法必须返回Symfony\Component\HttpFoundation\Request的对象,不然抛异常 $request = call_user_func(self::$requestFactory, $query, $request, $attributes, $cookies, $files, $server, $content); if (!$request instanceof self) { throw new \LogicException('The Request factory must return an instance of Symfony\Component\HttpFoundation\Request.'); } return $request; } return new static($query, $request, $attributes, $cookies, $files, $server, $content); } // 建立并返回\Illuminate\Http\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); } 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 ($query !== null) { $dup->query = new ParameterBag($query); } if ($request !== null) { $dup->request = new ParameterBag($request); } if ($attributes !== null) { $dup->attributes = new ParameterBag($attributes); } if ($cookies !== null) { $dup->cookies = new ParameterBag($cookies); } if ($files !== null) { $dup->files = new FileBag($files); } if ($server !== null) { $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; } public function getContent($asResource = false) { $currentContentIsResource = is_resource($this->content); if (PHP_VERSION_ID < 50600 && false === $this->content) { throw new \LogicException('getContent() can only be called once when using the resource return type and PHP below 5.6.'); } // 资源类型时的处理 if (true === $asResource) { if ($currentContentIsResource) { rewind($this->content); return $this->content; } // Content passed in parameter (test) if (is_string($this->content)) { $resource = fopen('php://temp', 'r+'); fwrite($resource, $this->content); rewind($resource); return $resource; } $this->content = false; return fopen('php://input', 'rb'); } if ($currentContentIsResource) { rewind($this->content); return stream_get_contents($this->content); } // 不然读取标准的输入字节流 if (null === $this->content || false === $this->content) { $this->content = file_get_contents('php://input'); } return $this->content; }
总之:最后建立了一个解析了$_GET, $_POST, $_COOKIE, $_FILES, $_SERVER等变量以后的IlluminateHttpRequest类的对象php
public function handle($request) { try { $request->enableHttpMethodParameterOverride(); $response = $this->sendRequestThroughRouter($request); } catch (Exception $e) { $this->reportException($e); $response = $this->renderException($request, $e); } catch (Throwable $e) { $this->reportException($e = new FatalThrowableError($e)); $response = $this->renderException($request, $e); } event(new Events\RequestHandled($request, $response)); return $response; } // 核心方法 protected function sendRequestThroughRouter($request) { // 注入请求对象到服务容器,供后期使用 $this->app->instance('request', $request); Facade::clearResolvedInstance('request'); // 启动应用(包括加载设置环境变量、加载配置文件、设置系统错误异常、Facade、启动各服务提供者的引导项等),后续分析 $this->bootstrap(); // 委托管道形式处理请求,这个是middleware实现的本质,后续分析 return (new Pipeline($this->app)) ->send($request) ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware) ->then($this->dispatchToRouter()); } public static function clearResolvedInstance($name) { unset(static::$resolvedInstance[$name]); } public function bootstrap() { if (! $this->app->hasBeenBootstrapped()) { $this->app->bootstrapWith($this->bootstrappers()); } } protected function bootstrappers() { ##################################################################### #$bootstrappers = [ # \Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class, # \Illuminate\Foundation\Bootstrap\LoadConfiguration::class, # \Illuminate\Foundation\Bootstrap\HandleExceptions::class, # \Illuminate\Foundation\Bootstrap\RegisterFacades::class, # \Illuminate\Foundation\Bootstrap\RegisterProviders::class, # \Illuminate\Foundation\Bootstrap\BootProviders::class, #]; ##################################################################### return $this->bootstrappers; } public function bootstrapWith(array $bootstrappers) { $this->hasBeenBootstrapped = true; foreach ($bootstrappers as $bootstrapper) { // 启动前的事件触发 $this['events']->fire('bootstrapping: '.$bootstrapper, [$this]); // 建立相应的对象并执行引导操做 $this->make($bootstrapper)->bootstrap($this); // 启动后的事件触发 $this['events']->fire('bootstrapped: '.$bootstrapper, [$this]); } } // 位于Illuminate\Events\Dispatcher文件,$payload用来传参给监听器,$halt表示是否终止后续事件的监听 public function fire($event, $payload = [], $halt = false) { return $this->dispatch($event, $payload, $halt); } public function dispatch($event, $payload = [], $halt = false) { list($event, $payload) = $this->parseEventAndPayload( $event, $payload ); // 若实现了广播类则加入广播队列 if ($this->shouldBroadcast($payload)) { $this->broadcastEvent($payload[0]); } $responses = []; // 获取此事件相关的监听事件函数 foreach ($this->getListeners($event) as $listener) { $response = $listener($event, $payload); // 触发事件 if (! is_null($response) && $halt) { return $response; } if ($response === false) { break; } $responses[] = $response; } return $halt ? null : $responses; } public function getListeners($eventName) { $listeners = isset($this->listeners[$eventName]) ? $this->listeners[$eventName] : []; $listeners = array_merge( $listeners, $this->getWildcardListeners($eventName) ); return class_exists($eventName, false) ? $this->addInterfaceListeners($eventName, $listeners) // 在$listeners增长接口监听事件 : $listeners; }
$this['events']含义参考[kernel对象化]:bootstrap
1. Illuminate\Foundation\Application extends Illuminate\Container\Container 2. Container implements ArrayAccess,故Application能够按数组形式读取。 3. public function offsetGet($key) { return $this->make($key); } 4. public function offsetSet($key, $value) { $this->bind($key, $value instanceof Closure ? $value : function () use ($value) { return $value; });} 5. public function __get($key) { return $this[$key]; } 6. public function __set($key, $value) { $this[$key] = $value; } 7. 因此$this['events'] 就是 $this->instances['events'] 对象($dispatcher); 8. 其余的$this['config']都是相似的。 9. $this['events']和$this->events同样,既能够数组形式访问,也能够按对象方式访问。
大致流程是: 建立获取请求对象(包括请求头和请求体)=>注入请求对象到服务容器=>配置系统运行环境=>发送请求segmentfault