Skip to content
PSR Standards Overview
step 1/7

Reading — step 1 of 7

Learn

~3 min readModern PHP 8+

The PHP-FIG (Framework Interop Group) maintains the PSR (PHP Standards Recommendations) — interfaces and conventions that let PHP libraries and frameworks work together. Knowing them is mandatory for any serious PHP work. Modern PHP and the PHP-FIG site are the references.

PSR-1 / PSR-12: coding style

Basic file structure rules:

  • Files MUST use <?php only (no closing ?> for class files)
  • Files MUST be UTF-8 without BOM
  • Class names: StudlyCaps
  • Method names: camelCase
  • Constants: ALL_UPPER_CASE
  • One class per file
  • 4-space indentation, soft tabs
  • 120-char line limit (soft), 80 (preferred)
  • Lots more — phpcs and php-cs-fixer enforce these automatically

Most teams configure their tooling to enforce PSR-12. Don't memorize the rules — let the tools do it.

PSR-4: Autoloading

The namespace-to-path mapping standard. With Composer:

// composer.json
{
  "autoload": {
    "psr-4": {
      "App\\": "src/",
      "App\\Tests\\": "tests/"
    }
  }
}

This says: \App\Foo\Bar lives at src/Foo/Bar.php. Composer generates an autoloader so new \App\Foo\Bar() automatically loads the file when first referenced.

In code:

namespace App\Services;

use App\Repositories\UserRepository;

class UserService { /* ... */ }

File lives at src/Services/UserService.php. The class's fully-qualified name is \App\Services\UserService.

PSR-3: Logger Interface

use Psr\Log\LoggerInterface;

interface LoggerInterface {
    public function emergency(string|\Stringable $message, array $context = []): void;
    public function alert(...): void;
    public function critical(...): void;
    public function error(...): void;
    public function warning(...): void;
    public function notice(...): void;
    public function info(...): void;
    public function debug(...): void;
    public function log($level, string|\Stringable $message, array $context = []): void;
}

Write to this interface and your code works with Monolog, Laravel's logger, Symfony's Logger Component — any compliant logger.

PSR-7: HTTP Messages

The interface set for HTTP requests/responses:

use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;

function handle(ServerRequestInterface $request): ResponseInterface {
    $name = $request->getQueryParams()['name'] ?? 'World';
    return new Response(200, [], "Hello, $name");
}

Used by Slim, modern Laravel routes, Mezzio, Guzzle. Standard interfaces let you swap HTTP libs.

PSR-15 layers on top — middleware:

use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

class AuthMiddleware implements MiddlewareInterface {
    public function process(
        ServerRequestInterface $request,
        RequestHandlerInterface $handler
    ): ResponseInterface {
        if (!$request->getHeaderLine('Authorization')) {
            return new Response(401);
        }
        return $handler->handle($request);
    }
}

PSR-11: Container Interface

use Psr\Container\ContainerInterface;

interface ContainerInterface {
    public function get(string $id): mixed;
    public function has(string $id): bool;
}

The DI container standard. Bind to this interface and your library works with Laravel's container, Symfony's, PHP-DI, etc.

PSR-6 / PSR-16: Cache

Two cache standards. PSR-6 is more powerful (item-based, deferred saves); PSR-16 is simpler (key-value):

use Psr\SimpleCache\CacheInterface;

interface CacheInterface {
    public function get(string $key, mixed $default = null): mixed;
    public function set(string $key, mixed $value, null|int|\DateInterval $ttl = null): bool;
    public function delete(string $key): bool;
    // ...
}

Why this matters

A PHP library that uses PSR interfaces can:

  • Work with any compliant framework (Laravel, Symfony, Slim, Mezzio)
  • Be tested with mock implementations
  • Be replaced without breaking dependents

"Code to interfaces, not implementations" is sound advice in any language. PSR makes those interfaces standardized so the PHP ecosystem composes.

Common mistakes

  • Importing implementations instead of PSR interfaces in library code — use Monolog\Logger; instead of use Psr\Log\LoggerInterface;. Hard-codes a dependency.
  • Forgetting PSR-12 in code reviews — let phpcs / php-cs-fixer automate enforcement.
  • Confusing PSR-4 (autoloading) with PSR-0 (deprecated) — PSR-0 is the older, retired standard. Use PSR-4.
  • Ignoring PSR-11 in custom containers — your container can't be used with libraries that expect a PSR-11 container.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…