Symfony HttpFoundation en PHP: Request, Response y el ciclo HTTP como objetos

El componente HttpFoundation de Symfony encapsula las superglobales $_GET, $_POST, $_FILES, $_COOKIE y $_SERVER en objetos orientados a objetos. Puedes usarlo en cualquier proyecto PHP sin instalar Symfony completo.

Instalación

composer require symfony/http-foundation

Request::createFromGlobals()

Reemplaza todas las superglobales con un único objeto:

<?php
use SymfonyComponentHttpFoundationRequest;

$request = Request::createFromGlobals();

// Equivalente a $_GET['pagina'] ?? 1
$pagina = $request->query->getInt('pagina', 1);

// Equivalente a $_POST['email'] ?? ''
$email = $request->request->get('email', '');

// Cabecera HTTP
$accept = $request->headers->get('Accept');

// Método HTTP
echo $request->getMethod();   // GET, POST, PUT…

// URL completa
echo $request->getUri();

// IP del cliente
echo $request->getClientIp();
?>

Bolsas de parámetros (ParameterBag)

Cada grupo de parámetros es una ParameterBag con métodos de acceso tipado:

<?php
$id    = $request->query->getInt('id');          // ?id=5 ? 5
$token = $request->headers->get('X-Api-Token');
$file  = $request->files->get('foto');           // UploadedFile
$cook  = $request->cookies->get('sesion');
?>

Response

<?php
use SymfonyComponentHttpFoundationResponse;

$response = new Response(
    '<h1>Hola</h1>',
    Response::HTTP_OK,
    ['Content-Type' => 'text/html']
);

$response->send();
?>

JsonResponse

<?php
use SymfonyComponentHttpFoundationJsonResponse;

$data = ['usuario' => 'Ana', 'activo' => true];

$response = new JsonResponse($data, 200);
// O equivalente:
$response = JsonResponse::fromJsonString(json_encode($data), 200);

$response->send();
?>

RedirectResponse

<?php
use SymfonyComponentHttpFoundationRedirectResponse;

// Redirigir con 302 (por defecto)
$response = new RedirectResponse('/login');

// Redirigir con 301 (permanente)
$response = new RedirectResponse('/nueva-url', 301);

$response->send();
?>

BinaryFileResponse

Descarga de ficheros con gestión de cabeceras correcta:

<?php
use SymfonyComponentHttpFoundationBinaryFileResponse;
use SymfonyComponentHttpFoundationResponseHeaderBag;

$response = new BinaryFileResponse('/var/datos/factura.pdf');
$response->setContentDisposition(
    ResponseHeaderBag::DISPOSITION_ATTACHMENT,
    'factura-2024.pdf'
);

$response->prepare($request);
$response->send();
?>

BinaryFileResponse gestiona automáticamente las cabeceras ETag, Last-Modified y soporta peticiones condicionales (If-None-Match).

StreamedResponse

Cuando el contenido se genera progresivamente (exportaciones grandes, logs en tiempo real):

<?php
use SymfonyComponentHttpFoundationStreamedResponse;

$response = new StreamedResponse(function () {
    $handle = fopen('php://output', 'w');
    fputcsv($handle, ['id', 'nombre', 'email']);
    for ($i = 1; $i <= 10000; $i++) {
        fputcsv($handle, [$i, "Usuario $i", "user{$i}@ejemplo.com"]);
        if ($i % 1000 === 0) {
            ob_flush();
            flush();
        }
    }
    fclose($handle);
});

$response->headers->set('Content-Type', 'text/csv');
$response->headers->set('Content-Disposition', 'attachment; filename="usuarios.csv"');
$response->send();
?>

Cookies

<?php
use SymfonyComponentHttpFoundationCookie;

$cookie = Cookie::create('preferencia')
    ->withValue('oscuro')
    ->withExpires(new DateTimeImmutable('+30 days'))
    ->withSecure(true)
    ->withHttpOnly(true)
    ->withSameSite('Strict');

$response->headers->setCookie($cookie);
$response->send();
?>

Mini front-controller

<?php
$request = Request::createFromGlobals();
$path    = $request->getPathInfo();
$method  = $request->getMethod();

$response = match (true) {
    $path === '/'          => new Response('Inicio', 200),
    $path === '/api/ping'  => new JsonResponse(['ok' => true]),
    default                => new Response('No encontrado', 404),
};

$response->send();
?>

Errores comunes

  • Headers already sent: llama a $response->send() antes de hacer cualquier echo o tener salida en el buffer.
  • getInt() devuelve 0 inesperadamente: el parámetro no existe o no es numérico. Usa el segundo argumento como valor por defecto.
  • BinaryFileResponse y Apache mod_xsendfile: en servidores con X-Sendfile, llama a $response->trustXSendfileTypeHeader() para delegar la descarga al servidor web.

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP