Введение: когда PHP повзрослел
Когда-то PHP был как подросток без режима дня — каждый писал, как хотел. Кто-то называл классы MyClass, кто-то my_class, а кто-то просто файлы с функциями пихал в /includes.
В 2009-м появился PHP-FIG (Framework Interop Group) — ребята из мира фреймворков (Symfony, Laravel, Zend, etc.), которые сказали:
«Давайте хоть как-то договоримся, чтобы наши библиотеки могли дружить».
Так родились PSR — PHP Standards Recommendations.
Не RFC, не законы, но стандарты, которые формируют “единый язык” между библиотеками и фреймворками.
Что сейчас актуально?
На момент 2025 года активно используются PSR-1, 2, 3, 4, 6, 7, 11, 12, 13, 14, 15, 17, 18, 19 и 20.
Некоторые устарели (например, PSR-0), но их дух живёт в новых версиях.
Давай разберёмся по-человечески, что они делают и зачем.
🧱 Базовые стандарты
PSR-1: Basic Coding Standard
Минимальные правила, чтобы код выглядел похоже.
- Классы — StudlyCaps (
UserController), - Методы — camelCase (
getUserById), - Константы — UPPER_SNAKE_CASE,
- Один класс = один файл.
Это просто “договорённость, чтобы глаза не кровили”.
💡 Технически: многие анализаторы (PHP_CodeSniffer, PHPStan) опираются на PSR-1 для базовых проверок.
PSR-12: Extended Coding Style
Наследник PSR-2, который добавил современности (short arrays, strict_types, nullable types).
Это стиль форматирования: где ставить фигурные скобки, как делать отступы, пробелы и т.д.
Пример:
declare(strict_types=1);
namespace App\Services;
use App\Models\User;
class UserService
{
public function findUser(int $id): ?User
{
return User::find($id);
}
}
💡 Если используешь Laravel Pint или PHP-CS-Fixer — они под капотом следуют PSR-12.
⚙️ Автозагрузка и структура
PSR-4: Autoloading Standard
Самый важный стандарт, без которого Composer не был бы тем, чем он есть.
Идея: пространство имён (namespace) = путь к файлу.
namespace App\Services;
class EmailSender {}
→ файл лежит по пути /src/Services/EmailSender.php.
💡 PSR-4 полностью заменил старый PSR-0.
Благодаря ему ты просто пишешь composer dump-autoload — и всё работает магией.
🧩 Взаимодействие между компонентами
PSR-3: Logger Interface
Единый интерфейс для логирования.
Неважно, Monolog или собственный логгер — если реализует Psr\Log\LoggerInterface, он совместим.
use Psr\Log\LoggerInterface;
class UserService {
public function __construct(private LoggerInterface $logger) {}
public function registerUser(array $data) {
$this->logger->info('User registered', $data);
}
}
💡 Laravel, Symfony, Slim, Monolog — все используют PSR-3.
PSR-11: Container Interface
Контейнер зависимостей с двумя методами:
$container->get('logger');
$container->has('logger');
Это базовый контракт для DI-контейнеров.
Laravel, Symfony, PHP-DI — все могут быть подменяемы, если следуют PSR-11.
PSR-13: Hypermedia Links
Для REST-API, где ссылки внутри данных — часть контракта.
Определяет интерфейсы для ссылок (LinkInterface) и коллекций ссылок (LinkProviderInterface).
💡 Реже встречается, но важен для HAL/JSON-LD API.
PSR-14: Event Dispatcher
Единый способ отправлять и слушать события:
$dispatcher->dispatch(new UserRegisteredEvent($user));
События — объекты, слушатели — обработчики.
Это слабое связывание между модулями (чистая архитектура рулит).
🌐 HTTP и middleware
PSR-7: HTTP Message Interfaces
Определяет интерфейсы для HTTP-запросов и ответов.
Фреймворки теперь говорят на одном языке:
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
💡 Symfony, Slim, Laravel (через bridges) — все поддерживают PSR-7.
PSR-15: HTTP Middleware
Определяет контракт для middleware:
interface MiddlewareInterface {
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface;
}
То есть ты можешь использовать middleware из любого фреймворка — оно просто работает.
PSR-17: HTTP Factories
Раньше у PSR-7 была проблема: как создавать объекты Request/Response, если интерфейс не говорит об этом.
PSR-17 добавил фабрики:
$request = $factory->createServerRequest('GET', '/users');
$response = $factory->createResponse(200);
PSR-18: HTTP Client
Интерфейс для HTTP-клиентов.
Теперь можно подменять Guzzle, Symfony HttpClient, Buzz — всё совместимо, если реализует Psr\Http\Client\ClientInterface.
$response = $client->sendRequest($request);
🧠 Новое поколение
PSR-19: PHPDoc Tags
Новый стандарт оформления аннотаций PHPDoc.
Упорядочивает то, как писать @param, @return, @throws.
Важен для IDE, статического анализа и автогенерации API.
PSR-20: Clock Interface
Свежий, но мощный.
Добавляет интерфейс Psr\Clock\ClockInterface:
interface ClockInterface {
public function now(): DateTimeImmutable;
}
Зачем?
Чтобы тестировать код, зависящий от времени. Можно подменять “время” в тестах или моках.
🧩 Итоговая картина
| Категория | PSR | Назначение |
|---|---|---|
| Код-стиль | PSR-1, PSR-12 | Единый вид кода |
| Автозагрузка | PSR-4 | Подключение классов |
| Логирование | PSR-3 | Общий интерфейс логгера |
| DI-контейнер | PSR-11 | Контракт контейнера |
| HTTP | PSR-7, 15, 17, 18 | Единые запросы, middleware и клиенты |
| События | PSR-14 | Диспетчер событий |
| Докблоки | PSR-19 | Формат PHPDoc |
| Время | PSR-20 | Единый интерфейс для часов |
| Гипермедиа | PSR-13 | Ссылки и HATEOAS |
Заключение: зачем это всё?
PSR — это не “правила ради правил”.
Это мост между библиотеками и фреймворками, благодаря которому можно свободно комбинировать пакеты без боли и костылей.
Если твой код совместим с PSR — он, как LEGO: всё щёлкает и собирается без напильника.
И в этом — взросление PHP.