SkillByAIOpen interactive version →

Lesson 13 / 25

The Request Lifecycle, PHP-FPM and Front Controllers

Explain how a request reaches PHP and how applications route it.

From NGINX to your code

In production, a web server such as NGINX receives the HTTP request, serves static files itself, and forwards PHP requests over FastCGI to PHP-FPM, which keeps a pool of worker processes ready. Each worker runs one request at a time: it bootstraps your application, handles the request and resets state. Request data is available through superglobals: $_GET (query string), $_POST (form bodies), $_SERVER (headers, method, URI), $_COOKIE, $_FILES and $_SESSION; JSON bodies are read from php://input. Modern applications use a front controller: every request goes to one public/index.php, which loads the autoloader, builds the application and passes the request to a router that maps method and path to a controller. Frameworks wrap superglobals in request and response objects (PSR-7 or framework-specific), which are easier to test. The web server's document root should be the public/ directory only, so source code, .env files and vendor/ are never directly reachable.

NGINX, PHP-FPM and the front controller

NGINX serves static files and forwards dynamic requests to PHP-FPM workers running index.php.

Figure 5.1 — Request flow from NGINX to PHP-FPM workers and the front controller.

A minimal front controller with routing

One entry point maps method and path to handlers.

<?php
// public/index.php
declare(strict_types=1);

require __DIR__ . '/../vendor/autoload.php';

$method = $_SERVER['REQUEST_METHOD'];
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);

$routes = [
    'GET /health'  => fn (): array => ['status' => 'ok'],
    'GET /orders'  => fn (): array => (new Shop\Orders\OrderQuery())->recent(),
    'POST /orders' => function (): array {
        $body = json_decode(file_get_contents('php://input'), true, flags: JSON_THROW_ON_ERROR);
        return (new Shop\Orders\PlaceOrder())->handle($body);
    },
];

$handler = $routes["{$method} {$path}"] ?? null;

header('Content-Type: application/json');
if ($handler === null) {
    http_response_code(404);
    echo json_encode(['error' => 'Not found']);
    exit;
}
echo json_encode($handler(), JSON_THROW_ON_ERROR);

// nginx: root /var/www/shop/public;  try_files $uri /index.php?$query_string;

Document root must be public/

If the web root is the project directory, a request for /.env or /vendor/composer/installed.json may download secrets and dependency details. Point the server at public/ only.

Quick check: In a typical production setup, which component runs PHP code for NGINX?

  • PHP-FPM via FastCGI
  • Apache Tomcat
  • Node.js
  • The browser
Answer

PHP-FPM via FastCGI — NGINX forwards PHP requests to PHP-FPM worker processes over FastCGI.