Reading — step 1 of 7
Learn
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
<?phponly (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 —
phpcsandphp-cs-fixerenforce 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 ofuse Psr\Log\LoggerInterface;. Hard-codes a dependency. - Forgetting PSR-12 in code reviews — let
phpcs/php-cs-fixerautomate 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…