Os Padrões PSR (PHP Standards Recommendations) são um conjunto de especificações criadas pelo PHP-FIG (PHP Framework Interop Group) para padronizar a forma como bibliotecas e frameworks PHP se comunicam e resolvem problemas comuns. Eles garantem que componentes de diferentes autores possam trabalhar juntos sem conflitos, promovendo interoperabilidade e boas práticas no ecossistema PHP.

Nesta aula, vamos explorar os padrões mais relevantes: os de estilo de código (PSR-1 e PSR-12), o de autoloading (PSR-4) e uma visão geral dos padrões HTTP (PSR-7 e PSR-15). Compreender esses padrões é fundamental para qualquer desenvolvedor PHP moderno, pois eles são adotados pela maioria dos frameworks (Laravel, Symfony, etc.) e bibliotecas populares.

O que são

Os Padrões PSR são recomendações que visam resolver problemas comuns no desenvolvimento PHP, como convenções de nomenclatura, estrutura de arquivos, carregamento automático de classes e padronização de interfaces para requisições e respostas HTTP. Eles não são obrigatórios, mas seguí-los facilita a colaboração e a reutilização de código.

O PHP-FIG é um grupo de projetos que inclui mantenedores de frameworks e bibliotecas renomadas. Eles discutem e votam propostas que, se aprovadas, tornam-se recomendações oficiais. Cada PSR é identificada por um número e pode ser marcada como 'Aceita', 'Em revisão' ou 'Depreciada'.

Para ilustrar, imagine que você está criando uma biblioteca que precisa ser usada em diferentes frameworks. Se você seguir a PSR-4, qualquer framework que respeite esse padrão poderá carregar suas classes automaticamente, sem configuração extra. Isso é essencial para a interoperabilidade.

PSR-1/PSR-12 (estilo)

A PSR-1 define as regras básicas de codificação, como a obrigatoriedade de tags PHP (<?php), uso de UTF-8 sem BOM, e a nomenclatura de classes, métodos e constantes. Ela é complementada pela PSR-12, que é uma extensão mais detalhada, substituindo a antiga PSR-2. Juntas, elas formam o guia de estilo oficial para código PHP.

Algumas regras importantes da PSR-1 incluem: arquivos devem usar apenas <?php ou <?=; classes devem ser nomeadas em StudlyCaps; métodos em camelCase; constantes em UPPER_CASE com underscores. A PSR-12 adiciona regras sobre indentação (4 espaços), chaves, espaçamento, uso de declare(strict_types=1) e muito mais.

Exemplo de código seguindo PSR-12:

<?php

declare(strict_types=1);

namespace App\Models;

use App\Contracts\ModelInterface;

class User implements ModelInterface
{
    private string $name;

    public function __construct(string $name)
    {
        $this->name = $name;
    }

    public function getName(): string
    {
        return $this->name;
    }
}

Perceba a indentação com 4 espaços, as chaves na mesma linha da declaração, os espaços após palavras-chave e a presença de declare(strict_types=1) no início do arquivo.

PSR-4 (autoload)

A PSR-4 especifica como as classes devem ser mapeadas para seus arquivos, permitindo o autoloading sem a necessidade de incluir manualmente cada arquivo. Ela define que a estrutura de namespaces deve corresponder à estrutura de diretórios, e que o prefixo do namespace é mapeado para um diretório base.

Por exemplo, se você tem o namespace App\ apontando para o diretório src/, a classe App\Models\User estará em src/Models/User.php. Isso é configurado no composer.json através da chave autoload.

Exemplo de configuração no composer.json:

{
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    }
}

Após rodar composer dump-autoload, o Composer gera o autoloader que carrega as classes automaticamente quando são referenciadas. Isso elimina a necessidade de require manual e melhora a organização do projeto.

Exemplo de uso:

<?php
require 'vendor/autoload.php';

$user = new \App\Models\User('João');
echo $user->getName();

Sem a PSR-4, você precisaria fazer require_once 'src/Models/User.php' antes de usar a classe. Com ela, o autoloader resolve a classe automaticamente.

PSR-7/PSR-15 (HTTP, visão geral)

A PSR-7 define interfaces padronizadas para mensagens HTTP, incluindo requisições (RequestInterface), respostas (ResponseInterface) e streams (StreamInterface). Ela permite que bibliotecas e frameworks manipulem HTTP de forma consistente, independentemente da implementação concreta.

A PSR-15 define interfaces para middleware, que são componentes que processam requisições e respostas em um pipeline. O middleware pode modificar a requisição, a resposta ou interromper o fluxo. Isso é fundamental para frameworks modernos como Laravel e Slim.

Exemplo de uso de PSR-7 com uma implementação como o Nyholm Psr7:

<?php
use Nyholm\Psr7\Factory\Psr17Factory;
use Nyholm\Psr7\ServerRequest;

$factory = new Psr17Factory();
$request = $factory->createServerRequest('GET', 'https://api.exemplo.com/users');
$response = $factory->createResponse(200);

Exemplo de um middleware PSR-15:

<?php
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Psr\Http\Server\MiddlewareInterface;

class AuthMiddleware implements MiddlewareInterface
{
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        if (!isset($_SESSION['user'])) {
            return new \Nyholm\Psr7\Response(401);
        }
        return $handler->handle($request);
    }
}

Esses padrões são a base para construir aplicações PHP modernas, desacopladas e testáveis.

Boas práticas e observações finais

Ao adotar os padrões PSR, você garante que seu código seja legível, interoperável e fácil de manter. Algumas boas práticas incluem: usar sempre a PSR-12 (ou PSR-1) como guia de estilo, configurar o autoload via Composer com PSR-4, e utilizar as interfaces PSR-7/PSR-15 em bibliotecas que manipulam HTTP.

Lembre-se de que os padrões evoluem, então consulte sempre a documentação oficial do PHP-FIG para estar atualizado. Além disso, ferramentas como PHP_CodeSniffer podem ajudar a verificar a conformidade com PSR-12 automaticamente.

Referências

Exercícios

  1. Explique a diferença entre PSR-1 e PSR-12. Dê um exemplo de regra que está na PSR-12 mas não na PSR-1.

    ✓ Resposta: A PSR-1 define as regras básicas, como nomenclatura de classes, métodos e constantes, e o uso de tags PHP. A PSR-12 é uma extensão mais detalhada, cobrindo indentação, espaçamento, uso de declare(strict_types=1), entre outros. Um exemplo de regra exclusiva da PSR-12 é a obrigatoriedade de usar 4 espaços para indentação, enquanto a PSR-1 não especifica isso.
  2. Como você configuraria o Composer para usar a PSR-4 para a namespace MinhaApp\ apontando para o diretório lib/?

    ✓ Resposta: No composer.json, adicione:
    {
        "autoload": {
            "psr-4": {
                "MinhaApp\\": "lib/"
            }
        }
    }
    Depois execute composer dump-autoload.
  3. Qual é a principal vantagem de usar a PSR-4 em relação ao autoload com require manual?

    ✓ Resposta: A PSR-4 permite o carregamento automático das classes, eliminando a necessidade de incluir manualmente cada arquivo com require. Isso facilita a manutenção, evita erros de caminho e permite que bibliotecas sejam usadas sem configuração adicional.
  4. Cite dois padrões PSR relacionados a HTTP e explique brevemente o que cada um define.

    ✓ Resposta: PSR-7 define interfaces para mensagens HTTP (requisições, respostas, streams), e PSR-15 define interfaces para middleware e request handlers. Juntas, elas permitem que aplicações processem HTTP de forma padronizada e componível.
  5. Escreva um exemplo de classe que implementa a interface MiddlewareInterface da PSR-15, que adiciona um cabeçalho à resposta.

    ✓ Resposta:
    <?php
    use Psr\Http\Message\ServerRequestInterface;
    use Psr\Http\Message\ResponseInterface;
    use Psr\Http\Server\RequestHandlerInterface;
    use Psr\Http\Server\MiddlewareInterface;
    
    class HeaderMiddleware implements MiddlewareInterface
    {
        public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
        {
            $response = $handler->handle($request);
            return $response->withHeader('X-Custom', 'Valor');
        }
    }