Skip to content

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 Response

Step by Step

1. Entry Point

Every request enters through public/index.php:

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:

  1. Creates the DI container
  2. Creates the router
  3. Creates the middleware pipeline
  4. Sets up error handling
  5. Registers core services
php
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:

php
$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:

php
$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:

php
$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:

php
$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:

php
// 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:

php
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:

php
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                            │
└─────────────────────────────────────────────────────────────┘

Released under the MIT License.