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.
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;
}