Laravel 4 Request/Response Lifecycle
Laravel encapsulates HTTP requests and responses within PHP objects. As you likely know, the HTTP core of Laravel revolves around Symfony's HTTPFoundation component.
I was curious about how Laravel creates a request, and finally how this gets turned into a response behind the scenes. Here's an (uncomprehensive) overview of what happens.
Bootstrap
First, unsuprisingly, the Application object is created. This is located at [Illuminate\Foundation\Application](https://github.com/laravel/framework/blob/master/src/Illuminate/Foundation/Application.php).Simply enough, the Request object is created in the __constructor method of the Application class.
/**
* Create a new Illuminate application instance.
*
* @return void
*/
public function __construct()
{
$this['request'] = Request::createFromGlobals();
// The exception handler class takes care of determining which of the bound
// exception handler Closures should be called for a given exception and
// gets the response from them. We'll bind it here to allow overrides.
$this->register(new ExceptionServiceProvider($this));
$this->register(new RoutingServiceProvider($this));
$this->register(new EventServiceProvider($this));
}
The Illuminate\Http\Request object extends Symfony\Component\HttpFoundation\Request.
The static method createFromGlobals is called, which uses the $_GET, $_POST, $_COOKIES, $_FILES and $_SERVER globals to create a populated Request object.
/**
* Creates a new request with values from PHP's super globals.
*
* @return Request A new request
*
* @api
*/
public static function createFromGlobals()
{
$request = new static($_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;
}
App::Run()
After bootstrap, the application runs. At this stage, we have a Request object populated and ready. Next, the request is dispatched; The application determines the route, does defined requested logic, and returns the appropriate output to the browser or console.App::run() is called, which first dispatches the created request object ($app['request']
). Illuminate\Routing\Router does the dispatching. It matches and runs a Illuminate\Routing\Route, and ultimately returns a Response object.
The Response object is generated at a call to Router::prepare(). This method takes a string of output returned from a route (Usually the output of a View), and passes that into a new Response object.
Lastly (almost), App::run() calls Response::send, which outputs the content to the browser or console.
public function send()
{
$this->sendHeaders();
$this->sendContent();
if (function_exists('fastcgi_finish_request')) {
fastcgi_finish_request();
} elseif ('cli' !== PHP_SAPI) {
// ob_get_level() never returns 0 on some Windows configurations, so if
// the level is the same two times in a row, the loop should be stopped.
$previous = null;
$obStatus = ob_get_status(1);
while (($level = ob_get_level()) > 0 && $level !== $previous) {
$previous = $level;
if ($obStatus[$level - 1] && isset($obStatus[$level - 1]['del']) && $obStatus[$level - 1]['del']) {
ob_end_flush();
}
}
flush();
}
return $this;
}