W świecie programowania, gdzie złożone projekty rozwijane są przez wielu programistów, spójność i przewidywalność kodu mają kluczowe znaczenie. W ekosystemie PHP rolę „strażników porządku” pełnią standardy PSR, czyli PHP Standards Recommendations. Ale czym tak naprawdę są PSR-y? I czy ich wpływ ogranicza się wyłącznie do PHP?
Czym są PSR-y?
PSR to zbiór rekomendacji opracowanych przez PHP-FIG (PHP Framework Interop Group). To grupa zrzeszająca twórców najpopularniejszych frameworków (np. Laravel, Symfony, Zend), której celem jest ułatwienie współpracy między bibliotekami i frameworkami poprzez ustalenie wspólnych standardów.
Każdy PSR ma swój numer, temat i status (np. „draft”, „accepted”, „deprecated”).
Oficjalne standardy PSR od PHP-FIG
PSR 1 Basic Coding Standard (Standardy kodowania)
PSR-1 w praktyce – jak pisać czysty i zgodny kod PHP
PSR-1, czyli Basic Coding Standard, to zbiór podstawowych wytycznych, które pomagają tworzyć czytelny i spójny kod PHP. Oto kilka kluczowych zasad wraz z przykładami:
- Kodowanie plików: Wszystkie pliki PHP powinny być zapisane w UTF-8 bez BOM.
Poprawnie: plik zapisany jako UTF-8 (np. w edytorze VS Code z odpowiednim ustawieniem kodowania). - Deklaracja przestrzeni nazw i
usetylko raz na plik:<?php namespace App\Controller;use App\Service\UserService; - Nazewnictwo klas: Klasy i interfejsy powinny być nazwane w stylu StudlyCaps (każde słowo zaczyna się wielką literą).
class UserProfile {} interface LoggerInterface {} - Nazewnictwo metod: Metody powinny być nazwane w stylu camelCase (pierwsze słowo małą literą, kolejne z wielkiej).
public function getUserById($id) {} - Autoloading zgodny z PSR-0 lub PSR-4: Nazwa klasy musi odpowiadać ścieżce pliku.
App\Model\Productpowinna znajdować się w plikusrc/Model/Product.php - Pliki PHP zawierają albo kod, albo deklaracje (np. klas), ale nie oba jednocześnie:
nie mieszaj logiki aplikacji z definicjami klas.
Stosowanie PSR-1 to pierwszy krok w stronę profesjonalnego kodowania w PHP. Dzięki tym zasadom projekty są bardziej przejrzyste, łatwiejsze do utrzymania i zgodne ze standardami nowoczesnych frameworków takich jak Laravel, Symfony czy Zend.
PSR 3 Logger Interface (Standardy logowania)
Jego celem jest zapewnienie wspólnego interfejsu LoggerInterface, dzięki któremu dowolna biblioteka PHP może logować zdarzenia niezależnie od konkretnego narzędzia logującego, np. Monolog czy własnego systemu logów.
Kluczowe założenia PSR-3:
debug()
Standardowy interfejs logowania: PSR-3 definiuje interfejs Psr\Log\LoggerInterface, który zawiera 8 metod odpowiadających różnym poziomom logowania:
emergency()
alert()
critical()
error()
warning()
notice()
info()
PSR-4 Autoloading Standard (Standardy autoloading)
PSR-4 Umożliwia on automatyczne ładowanie klas na podstawie ich przestrzeni nazw (namespace) i struktury katalogów – bez konieczności ręcznego dołączania plików przy pomocy require lub include.
Główne założenia PSR-4:
src/Controller/HomeController.php
- Przestrzeń nazw odpowiada strukturze katalogów:
Jeśli klasa ma pełną nazwęApp\Controller\HomeController, to zgodnie z PSR-4 powinna znajdować się w pliku: - Rejestracja autoloadera w
composer.json:
W plikucomposer.jsonmapujesz przestrzeń nazw do konkretnego katalogu:{ "autoload": { "psr-4": { "App\\": "src/" } } }
Następnie wykonujesz komendę:composer dump-autoload - Przykład klasy zgodnej z PSR-4:
Plik:src/Service/Mailer.phpnamespace App\Service; class Mailer { public function send($to, $message) { // logika wysyłki }}
Automatyczne ładowanie:
Po zdefiniowaniu wcomposer.jsoni załadowaniu autoloadera:
require_once 'vendor/autoload.php';
use App\Service\Mailer;
$mailer = new Mailer();
$mailer->send('user@example.com', 'Witaj!');
PSR-6 Caching Interface (Interfejsy Caching)
Dzięki PSR-6 różne komponenty i frameworki mogą korzystać z wymiennych adapterów cache bez konieczności przepisywania kodu. To podejście pozwala na czystsze, bardziej modularne i elastyczne zarządzanie pamięcią podręczną w aplikacjach PHP. Najważniejsze elementy PSR-6:
CacheItemInterface – reprezentuje pojedynczy wpis cache.
Interfejsy zdefiniowane przez PSR-6:
CacheItemPoolInterface – zarządza grupą wpisów cache (pula)
Podstawowe operacje Cache (przykład)
use Psr\Cache\CacheItemPoolInterface;
class ProductService
{
private CacheItemPoolInterface $cache;
public function __construct(CacheItemPoolInterface $cache)
{
$this->cache = $cache;
}
public function getProduct($id)
{
$item = $this->cache->getItem('product_' . $id);
if ($item->isHit()) {
return $item->get(); // Zwraca dane z cache
}
// Jeśli brak danych w cache – pobierz z bazy
$product = $this->fetchFromDatabase($id);
$item->set($product)->expiresAfter(3600);
$this->cache->save($item);
return $product;
}
}
- Cechy PSR-6:
- Cache działa na podstawie identyfikatorów kluczy (np.
user_123,article_5), - Obsługuje wygasanie (TTL), usuwanie wpisów i przechowywanie obiektów,
- Pozwala na pełne zarządzanie pulą cache (np. czyszczenie, pobieranie wielu elementów naraz).
- Cache działa na podstawie identyfikatorów kluczy (np.
Dlaczego warto używać PSR-6?
Stosując PSR-6, Twój kod staje się niezależny od konkretnego systemu cache (np. Redis, Memcached, APCu, plikowego). Możesz łatwo wymieniać implementacje – np. z Symfony Cache na Doctrine Cache – bez zmiany logiki biznesowej. To podejście zgodne z zasadami czystej architektury i solidnych praktyk projektowych.
PSR-7 HTTP Message Interface (Interfejsy HTTP)
PSR-7 (HTTP Message Interface) to standard, który definiuje interfejsy dla reprezentowania żądań i odpowiedzi HTTP w aplikacjach PHP. Głównym celem PSR-7 jest unifikacja sposobu, w jaki aplikacje i middleware przetwarzają dane HTTP – niezależnie od używanego frameworka.
Najważniejsze interfejsy PSR-7:
Psr\Http\Message\RequestInterface– reprezentuje żądanie HTTP,Psr\Http\Message\ResponseInterface– reprezentuje odpowiedź HTTP,Psr\Http\Message\ServerRequestInterface– rozszerzenieRequestInterfacez danymi serwera,Psr\Http\Message\StreamInterface– do obsługi ciała (body) wiadomości.
Przykład użycia (np. z frameworkiem zgodnym z PSR-7):
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
function handleRequest(ServerRequestInterface $request): ResponseInterface
{
$name = $request->getQueryParams()['name'] ?? 'Gość';
$responseBody = "Witaj, {$name}!";
$response = new \GuzzleHttp\Psr7\Response();
$response->getBody()->write($responseBody);
return $response;
}
PSR-7 to kluczowy standard dla każdego, kto buduje nowoczesne aplikacje HTTP w PHP – czy to API, middleware, czy pełne systemy webowe. Jeśli planujesz tworzyć aplikacje oparte na architekturze middleware lub REST, znajomość PSR-7 jest niezbędna.
PSR-11 Container Interface
PSR-11 definiuje standardowy interfejs dla kontenerów zależności (Dependency Injection Containers) w PHP. Zamiast wiązać się z konkretną implementacją (np. Symfony DI, Laravel Service Container), możesz korzystać z jednolitego interfejsu ContainerInterface, co zwiększa przenośność i elastyczność Twojej aplikacji.
Główne metody interfejsu Psr\Container\ContainerInterface:
get(string $id): mixed– zwraca instancję usługi o podanym identyfikatorze,has(string $id): bool– sprawdza, czy kontener może zwrócić usługę o podanym identyfikatorze.
Przykład – jak to wygląda w praktyce:
use Psr\Container\ContainerInterface;
class UserController
{
private UserService $userService;
public function __construct(ContainerInterface $container)
{
$this->userService = $container->get(UserService::class);
}
public function show(int $id)
{
$user = $this->userService->find($id);
// ...
}
}
Zalety stosowania PSR-11:
- Zgodność z frameworkami: Symfony, Laravel, Slim, Laminas – wszystkie wspierają kontenery zgodne z PSR-11.
- Wymienność: Możesz łatwo podmienić kontener na inny (np. PHP-DI, Pimple), o ile implementuje
ContainerInterface. - Luźne powiązania: PSR-11 promuje dependency inversion – klasy nie zależą od konkretnej implementacji kontenera, tylko od jego interfejsu.
PSR-12 Extended Coding Style Guide
PSR-12 to rozwinięcie wcześniejszego standardu PSR-1, które szczegółowo określa zasady formatowania i stylu kodu w PHP. Jego celem jest zapewnienie spójności kodu w projektach – niezależnie od liczby programistów, frameworka czy edytora. Dzięki PSR-12 kod jest bardziej czytelny, uporządkowany i łatwiejszy do utrzymania.
Najważniejsze zasady PSR-12 w praktyce:
<?php
declare(strict_types=1);
namespace Vendor\Package;
use Vendor\Package\{ClassA as A, ClassB, ClassC as C};
use Vendor\Package\SomeNamespace\ClassD as D;
use function Vendor\Package\{functionA, functionB, functionC};
use const Vendor\Package\{ConstantA, ConstantB, ConstantC};
class Foo extends Bar implements FooInterface
{
public function sampleFunction(int $a, int $b = null): array
{
if ($a === $b) {
bar();
} elseif ($a > $b) {
$foo->bar($arg1);
} else {
BazClass::bar($arg2, $arg3);
}
}
final public static function bar()
{
// method body
}
}
Najważniejsze zasady PSR-12 w praktyce:
- Deklaracja
<?phptylko jako pełna otwierająca: - Tylko jeden
namespacena plik i umieszczony podeclare: <?php declare(strict_types=1);namespace App\Controller;- Kolejność
use:- Najpierw
usedla klas, - potem
use function, - na końcu
use const, - każda grupa oddzielona pustą linią.
- Najpierw
- Deklaracje klas i metod:
- Klasa, funkcja i metoda powinny mieć pustą linię przed i po,
- Nawiasy klamrowe
{}zawsze w nowej linii
class UserController { public function index(): void { echo 'Witaj'; } } - Wcięcia: 4 spacje zamiast tabulatorów.
- Łamanie długich linii: Maksymalna długość linii to 120 znaków (zalecane), a dla lepszej czytelności – 80 znaków w komentarzach.
PSR-14 Event Dispatcher
PSR-14, który definiuje sposób obsługi zdarzeń (eventów) w aplikacjach. Dzięki niemu można w elegancki sposób oddzielić logikę zdarzeń od głównej aplikacji, co ułatwia rozwój i testowanie kodu.
Dzięki niemu można w elegancki sposób oddzielić logikę zdarzeń od głównej aplikacji, co ułatwia rozwój i testowanie kodu.
Jak to działa?
- Komponentem centralnym jest EventDispatcherInterface, który rozsyła zdarzenia do zarejestrowanych listenerów (nasłuchujących funkcji).
- Zdarzenia to zwykłe obiekty PHP — mogą być modyfikowalne lub nie, zależnie od potrzeb.
- Listenery reagują na zdarzenia w sposób decentralizowany, co pozwala uniknąć sztywnego powiązania klas.
Dlaczego warto używać?
- Lepsza modularność i czytelność kodu.
- Możliwość łatwego rozszerzania funkcjonalności bez modyfikacji istniejącego kodu.
- PSR-14 jest neutralny względem frameworka, więc działa np. w Symfony, Laravelu, jak i we własnych projektach.
PSR-16 Simple Cache
PSR-16 który definiuje prosty interfejs do korzystania z cache (pamięci podręcznej) w aplikacjach. W odróżnieniu od bardziej rozbudowanego PSR-6, PSR-16 stawia na łatwość użycia i prostotę.
Co daje PSR-16?
- Jednolity interfejs
CacheInterfacez takimi metodami jak:get($key)set($key, $value, $ttl)delete($key)clear()has($key)
- Można łatwo wymieniać implementacje cache, np. Redis, Memcached czy pliki, bez zmiany logiki aplikacji.
- Idealny do prostych projektów, mikroserwisów lub szybkiej integracji.
Dlaczego warto?
- Prosty i przejrzysty API – minimum metod, maksimum efektu.
- Wspierany przez wiele gotowych bibliotek (np. Symfony Cache, Laravel Cache przez adaptery).
- Ułatwia pisanie czytelnego i testowalnego kodu.
PSR-17 HTTP Factories
PSR-17 to standard, który wprowadza zestaw fabryk (factories) do tworzenia obiektów związanych z HTTP – takich jak requesty, response’y, URI czy strumienie. Stanowi uzupełnienie PSR-7, który definiuje te obiekty, ale nie mówi, jak je tworzyć.
Co obejmuje PSR-17?
PSR-17 definiuje interfejsy dla fabryk:
RequestFactoryInterfaceResponseFactoryInterfaceServerRequestFactoryInterfaceStreamFactoryInterfaceUploadedFileFactoryInterfaceUriFactoryInterface
Każda z nich odpowiada za tworzenie obiektów HTTP zgodnych z PSR-7.
Dlaczego to ważne?
- Ułatwia tworzenie obiektów HTTP w sposób zgodny z PSR-7.
- Umożliwia wymienność bibliotek – np. możesz zamienić Guzzle na Nyholm PSR7 bez zmiany reszty kodu.
- Zapewnia czystą separację logiki od implementacji.
Przykład użycia:
$responseFactory = new \Nyholm\Psr7\Factory\Psr17Factory();
$response = $responseFactory->createResponse(200, 'OK');
PSR-18 HTTP Client
PSR-18 to standard, który definiuje interfejs dla klienta HTTP. W przeciwieństwie do PSR-7 (który opisuje strukturę żądań i odpowiedzi) i PSR-17 (fabryki), PSR-18 skupia się na wysyłaniu requestów HTTP.
Jak działa?
Główna rola PSR-18 to interfejs:
HttpClientInterface
z jedną metodą: phpKopiujEdytujpublic function sendRequest(RequestInterface $request): ResponseInterface;
Dzięki temu możesz tworzyć żądania HTTP (np. GET, POST) i wysyłać je niezależnie od konkretnej biblioteki – Guzzle, Symfony HTTP Client czy HTTPlug.
Dlaczego warto?
- Neutralność – możesz wymienić implementację klienta HTTP bez zmian w kodzie.
- Integracja z PSR-7 i PSR-17 – wspólnie tworzą solidny, nowoczesny system komunikacji HTTP.
- Ułatwia tworzenie testowalnych, modularnych aplikacji.
Przykład:
$client = new \GuzzleHttp\Client();
$request = (new \Nyholm\Psr7\Factory\Psr17Factory())->createRequest('GET', 'https://example.com');
$response = $client->sendRequest($request); // dzięki adapterowi PSR-18
PSR-20 Clock
PSR-20 to z kolei standard, który wprowadza interfejs zegara (ClockInterface) jako sposób na uzyskiwanie aktualnego czasu w bardziej elastyczny, testowalny sposób.
Główna idea
Zamiast wywoływać w kodzie new \DateTimeImmutable() lub time(), PSR-20 pozwala używać obiektu zegara:
$clock = new SystemClock();
$now = $clock->now(); // Zwraca DateTimeImmutable
Kluczowy interfejs:
Edytujinterface ClockInterface {
public function now(): \DateTimeImmutable;
}
Dlaczego to ma sens?
- Ułatwia testowanie (np. można podmienić zegar na taki, który zawsze zwraca określoną godzinę).
- Zwiększa czytelność i spójność kodu.
- Pozwala na łatwą zamianę zegara systemowego na niestandardowy – np. do symulacji czasu, stref czasowych, itp.
Przykład użycia w testach:
class FrozenClock implements ClockInterface {
public function __construct(private \DateTimeImmutable $fixedTime) {}
public function now(): \DateTimeImmutable {
return $this->fixedTime;
}
}
Po co stosować PSR-y?
PSR-y jak większość standardów w życiu lub w pracy pomagają dogadać się i obrać prawidłowy kierunek – sposób na rozwiązanie problemu biznesowego. Głównymi plusami jego są:
Czytelność kodu – Każdy programista szybciej zrozumie kod napisany według znanego standardu.
Lepsza współpraca zespołowa – Spójny kod to mniej konfliktów i nieporozumień.
Łatwiejsze korzystanie z bibliotek – Frameworki i pakiety używają PSR-ów, więc integracja jest bezproblemowa.
Wysoka jakość kodu – Standaryzacja minimalizuje błędy i nieczytelne rozwiązania.
