Какому из стандартов PSR не следует Symfony?

Ответ

Symfony не реализует PSR-7 (HTTP Message Interfaces) нативно в своем ядре. Вместо этого он использует собственный, более ранний и функционально богатый компонент HttpFoundation.

Почему Symfony выбрал этот путь:

  1. Исторические причины: Компонент HttpFoundation был создан и стабилизирован задолго до принятия PSR-7. Переписать весь фреймворк и экосистему бандлов под новый стандарт был бы крайне затратным.
  2. Различия в философии: PSR-7 требует, чтобы объекты запроса и ответа были иммутабельными (неизменяемыми). Это хорошо для middleware-архитектуры, но может быть менее удобно и немного медленнее для традиционного MVC, где объекты запроса часто модифицируются (например, добавляются атрибуты). Объекты Symfony Request и Responseмутабельны.
  3. Удобство API: HttpFoundation предоставляет множество удобных методов "из коробки" для работы с сессиями, файлами, локалями, которые в PSR-7 потребовали бы дополнительных библиотек.

Пример работы с Symfony Request:

use SymfonyComponentHttpFoundationRequest;
use SymfonyComponentHttpFoundationJsonResponse;

// Request создается из глобальных переменных
$request = Request::createFromGlobals();

// Удобный доступ к данным
$id = $request->query->get('id'); // GET-параметр
$content = $request->request->get('name'); // POST-параметр
$file = $request->files->get('avatar'); // Загруженный файл
$header = $request->headers->get('Authorization');

// Мутабельность: можно добавить атрибут для передачи данных во внутренние слои
$request->attributes->set('_controller', 'AppControllerApiController::show');

// Ответ также прост
$response = new JsonResponse(['status' => 'success', 'id' => $id]);
$response->setStatusCode(201);
$response->headers->set('Cache-Control', 'no-cache');

Совместимость с PSR-7: Несмотря на это, Symfony обеспечивает полную совместимость через отдельные компоненты. Если вам нужно работать с библиотекой, требующей PSR-7 (например, многие PSR-15 middleware), вы можете использовать:

  • symfony/psr-http-message-bridge: Конвертирует объекты HttpFoundation в PSR-7 и обратно.
  • nyholm/psr7: Легковесная и быстрая реализация PSR-7, рекомендованная для использования с Symfony.

Таким образом, вы можете разрабатывать приложение на привычном HttpFoundation, а на уровне контроллера или при интеграции с внешними компонентами легко конвертировать запросы и ответы.

Ответ 18+ 🔞

А, ну это классика, блядь! Сейчас объясню на пальцах, почему у Симфони своя атмосфера, а не этот ваш PSR-7.

Представь себе: есть старый, проверенный дедовский HttpFoundation. Он появился, когда про PSR-7 ещё и в проекте не было, ёпта. И он работал, работает и будет работать — удобный, как родной тапок. А потом приходят эти умники с PSR-7 и говорят: «А давайте сделаем всё иммутабельным!». То есть, раз создал объект запроса — иди нахуй, больше его не трогай. Хочешь что-то изменить — создавай новый, целый, блядь, объект.

Ну и кому это надо в обычном-то MVC, я спрашиваю? У меня в контроллере часто нужно в запрос какой-нибудь атрибут воткнуть, чтобы потом в сервисе его вытащить. А по PSR-7 — хуй там, а не атрибут. Придётся новый объект городить. Это ж какая писанина, мать его! И производительность подумай — копировать целый объект вместо того, чтобы одно поле поменять.

Вот Симфони и не стала ломать свою огромную экосистему и переписывать всё под эту моду. Зачем, если своя бандура и так огонь? Смотри, как просто:

use SymfonyComponentHttpFoundationRequest;
use SymfonyComponentHttpFoundationJsonResponse;

// Всё из глобальных переменных само натягивается — красота!
$request = Request::createFromGlobals();

// Достаём данные — элементарно, Ватсон!
$id = $request->query->get('id'); // Гет-параметр
$name = $request->request->get('name'); // Пост-параметр
$file = $request->files->get('avatar'); // Файл, ёбана!
$header = $request->headers->get('Authorization'); // Заголовок

// А вот и фишка — мутабельность! Подкинул атрибут и пошёл дальше.
$request->attributes->set('_controller', 'AppControllerApiController::show');

// Ответ — тоже не надо мозги выебывать.
$response = new JsonResponse(['status' => 'success', 'id' => $id]);
$response->setStatusCode(201); // Меняем статус когда захотим
$response->headers->set('Cache-Control', 'no-cache'); // И заголовки тоже

Прямо как живой, всё под рукой, ни одной лишней телодвижения. Удобство — овердохуища!

Но! Если вдруг тебе надо именно PSR-7 (какой-нибудь внешний middleware упоротый требует), то Симфони не бросит в беде. Есть мосты, ёпта!

Поставишь symfony/psr-http-message-bridge — и он будет как переводчик между твоим родным HttpFoundation и этим стерильным PSR-7. Сделал запрос по-старому, конвертнул в PSR-7, отдал в чужую библиотеку, получил ответ — и обратно конвертнул в родной формат. Всё прозрачно.

А для скорости ещё и nyholm/psr7 посоветуют — лёгкая реализация, без этих ваших наворотов.

Короче, суть: Симфони не использует PSR-7, потому что у неё есть свой, более удобный и исторически сложившийся инструмент. Но если очень приспичит — всегда можно натянуть совместимость, без проблем. Не парься.