Request Lifecycle
Overview
Understanding how a request flows through Lighthouse helps you debug issues and extend the framework effectively.
HTTP Request
↓
index.php (Entry Point)
↓
Application::run()
↓
ServerRequest::fromGlobals()
↓
ErrorMiddleware
↓
Middleware Pipeline
↓
Router::dispatch()
↓
Controller Action
↓
Response
↓
HTTP ResponseStep by Step
1. Entry Point
Every request enters through public/index.php:
<?php
require __DIR__ . '/../vendor/autoload.php';
use Lighthouse\Application;
$app = new Application(
basePath: dirname(__DIR__),
debug: true
);
// Configuration...
$app->run();2. Application Bootstrap
The Application constructor:
- Creates the DI container
- Creates the router
- Creates the middleware pipeline
- Sets up error handling
- Registers core services
public function __construct(string $basePath = '', bool $debug = false)
{
$this->container = new Container();
$this->router = new Router();
$this->pipeline = new Pipeline();
$this->errorHandler = new ErrorHandler($debug, ...);
$this->registerCoreBindings();
}3. Request Creation
run() creates a PSR-7 request from PHP globals:
$request = ServerRequest::fromGlobals();This captures:
- HTTP method
- URI and query string
- Headers
- Body content
- Uploaded files
4. Error Handling Wrapper
The request is wrapped in error middleware:
$errorMiddleware = new ErrorMiddleware($this->errorHandler);
$response = $errorMiddleware->process($request, $this);Any exception thrown downstream is caught and converted to an error response.
5. Middleware Pipeline
The request passes through each registered middleware:
$this->pipeline->pipe(new AuthMiddleware());
$this->pipeline->pipe(new CorsMiddleware());Each middleware can:
- Inspect/modify the request
- Short-circuit with a response
- Pass to the next handler
- Inspect/modify the response
6. Route Matching
The router matches the request to a route:
$match = $this->router->dispatch($request);This returns:
- The matched route
- Extracted parameters
- The route handler
If no route matches: RouteNotFoundException
If method not allowed: MethodNotAllowedException
7. Controller Dispatch
The handler is resolved and invoked:
// Resolve controller from container
$controller = $this->container->get(UserController::class);
// Call method with injected parameters
$response = $this->container->call($controller, 'show', $params);The container automatically injects:
- Route parameters (
{id}→$id) - The request object
- Any type-hinted dependencies
8. Response Preparation
The handler's return value is converted to a response:
private function prepareResponse(mixed $result): ResponseInterface
{
// Already a Response? Return it.
if ($result instanceof ResponseInterface) {
return $result;
}
// String? Wrap in Response.
if (is_string($result)) {
$response = new Response();
$response->getBody()->write($result);
return $response;
}
// Array? JSON encode.
if (is_array($result)) {
return $this->json($result);
}
}9. Response Sending
Finally, the response is sent to the client:
private function send(ResponseInterface $response): void
{
// Status line
header("HTTP/1.1 {$response->getStatusCode()} {$response->getReasonPhrase()}");
// Headers
foreach ($response->getHeaders() as $name => $values) {
foreach ($values as $value) {
header("{$name}: {$value}", false);
}
}
// Body
echo $response->getBody();
}Visual Flow
┌─────────────────────────────────────────────────────────────┐
│ HTTP Request │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ public/index.php │
│ Application::run() │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ Error Middleware │
│ (catches all exceptions) │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ Middleware Pipeline │
│ Auth → CORS → Logging → ... → Handler │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ Router │
│ Match URL → Extract params │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ Controller │
│ Resolve → Inject deps → Call method │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ Response │
│ View / JSON / Redirect │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ HTTP Response │
└─────────────────────────────────────────────────────────────┘