Введение в PSR стандарты
PSR (PHP Standards Recommendations) - это набор стандартов, разработанных PHP-FIG (PHP Framework Interoperability Group) для обеспечения совместимости между различными PHP-компонентами и фреймворками.
Основные PSR стандарты:
PSR-1: Basic Coding Standard
PSR-2: Coding Style Guide (устарел, заменен на PSR-12)
PSR-3: Logger Interface
PSR-4: Autoloading Standard
PSR-6: Caching Interface
PSR-7: HTTP Message Interface
PSR-11: Container Interface
PSR-12: Extended Coding Style Guide
PSR-15: HTTP Handlers
PSR-16: Simple Cache
Детальный разбор ключевых стандартов
PSR-1: Basic Coding Standard
Основные требования:
Файлы должны использовать только <?php или <?= теги
Файлы должны быть в UTF-8 без BOM
Файлы должны либо объявлять символы (классы, функции, константы), либо производить побочные эффекты (вывод, изменение ini и т.д.), но не то и другое вместе
Имена классов в стиле StudlyCaps
Константы класса в верхнем регистре с подчеркиваниями
Методы в стиле camelCase
Пример плохого кода:
<?ph
// Побочный эффект: изменение настроек
ini_set('display_errors', 0);
// Объявление
class bad_example {
const badCONSTANT = 'value';
public function badmethod() {
// ...
}
}
Хороший пример по PSR-1:
<?php
// Только объявления
class GoodExample
{
const GOOD_CONSTANT = 'value';
public function goodMethod()
{
// ...
}
}
// Другой файл:
<?php
// Только побочные эффекты
ini_set('display_errors', 0);
echo "Hello World";
PSR-12: Extended Coding Style Guide
Расширенное руководство по стилю кода, заменяет PSR-2.
Основные правила:
Использование 4 пробелов для отступов
Открывающая фигурная скобка класса на новой строке
Открывающая фигурная скобка метода на новой строке
Видимость должна быть объявлена для всех свойств и методов
Ключевые слова в нижнем регистре (true, false, null)
Строгий тип (strict_types=1) рекомендуется
Пример класса по PSR-12:
<?php
declare(strict_types=1);
namespace Vendor\Package;
use Vendor\Package\SomeNamespace\ClassA;
use Vendor\Package\SomeNamespace\ClassB;
use Vendor\Package\SomeNamespace\ClassC as C;
class Example
{
private const SOME_CONST = 'constant';
private $property;
public function __construct($property)
{
$this->property = $property;
}
public function someMethod(): string
{
if ($this->property === null) {
return 'null';
}
if ($this->property === 'value') {
return 'value';
}
return $this->property;
}
}
PSR-4: Autoloader Standard
Стандарт автозагрузки классов. Основные концепции:
Полное имя класса имеет вид: \<NamespaceName>(\<SubNamespaceNames>)*\<ClassName>
Пространства имен соответствуют структуре директорий
Имя класса должно совпадать с именем файла
Пример структуры проекта:
project/
src/
Acme/
Blog/
Post.php
Comment.php
vendor/
...
Post.php:
<?php
namespace Acme\Blog;
class Post
{
// ...
}
composer.json:
{
"autoload": {
"psr-4": {
"Acme\\Blog\\": "src/Acme/Blog"
}
}
}
PSR-3: Logger Interface
Стандартизированный интерфейс для логгеров.
Пример использования:
<?php
use Psr\Log\LoggerInterface;
class Application
{
private $logger;
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
public function run()
{
try {
// код приложения
$this->logger->info('Application started');
} catch (\Exception $e) {
$this->logger->error('Error occurred', ['exception' => $e]);
}
}
}
PSR-7: HTTP Message Interface
Стандартизированные интерфейсы для HTTP-сообщений (запросов и ответов).
Пример middleware:
<?php
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
class AuthenticationMiddleware implements MiddlewareInterface
{
public function process(
ServerRequestInterface $request,
RequestHandlerInterface $handler
): ResponseInterface {
if (!$this->isAuthenticated($request)) {
return new Response(401, [], 'Unauthorized');
}
return $handler->handle($request);
}
private function isAuthenticated(ServerRequestInterface $request): bool
{
// Проверка аутентификации
}
}
Лучшие практики
1. Использование strict_types
<?php
declare(strict_types=1);
function add(int $a, int $b): int
{
return $a + $b;
}
// Будет ошибка TypeError, если передать не integer
add(1, 2); // OK
add("1", "2"); // TypeError
2. Правильное использование пространств имен
<?php
namespace Acme\Blog\Domain\Model;
use Acme\Blog\Domain\Repository\PostRepository;
use Acme\Blog\Domain\Exception\InvalidTitleException;
class Post
{
private $title;
private $content;
public function __construct(string $title, string $content)
{
if (empty($title)) {
throw new InvalidTitleException('Title cannot be empty');
}
$this->title = $title;
$this->content = $content;
}
// ...
}
3. Использование интерфейсов PSR
<?php
namespace Acme\Blog\Infrastructure\Persistence;
use Psr\Log\LoggerInterface;
use Acme\Blog\Domain\Repository\PostRepository;
use Acme\Blog\Domain\Model\Post;
class DoctrinePostRepository implements PostRepository
{
private $logger;
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
public function save(Post $post): void
{
try {
// Сохранение поста
$this->logger->info('Post saved', ['id' => $post->getId()]);
} catch (\Exception $e) {
$this->logger->error('Error saving post', ['exception' => $e]);
throw $e;
}
}
}
4. Middleware подход с PSR-15
<?php
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
class CorsMiddleware implements MiddlewareInterface
{
public function process(
ServerRequestInterface $request,
RequestHandlerInterface $handler
): ResponseInterface {
$response = $handler->handle($request);
return $response
->withHeader('Access-Control-Allow-Origin', '*')
->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
->withHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
}
}
5. Кэширование с PSR-6
<?php
use Psr\Cache\CacheItemPoolInterface;
class ExpensiveCalculationService
{
private $cache;
public function __construct(CacheItemPoolInterface $cache)
{
$this->cache = $cache;
}
public function calculate(string $key): float
{
$item = $this->cache->getItem($key);
if ($item->isHit()) {
return $item->get();
}
$result = $this->doExpensiveCalculation();
$item->set($result);
$item->expiresAfter(3600); // 1 час
$this->cache->save($item);
return $result;
}
private function doExpensiveCalculation(): float
{
// Тяжелые вычисления
usleep(500000); // Имитация долгого расчета
return 42.0;
}
}
Заключение
Следование PSR стандартам и лучшим практикам PHP позволяет:
Обеспечить совместимость между разными компонентами
Улучшить читаемость и поддерживаемость кода
Упростить командную разработку
Создавать более надежное и предсказуемое ПО
Внедрение этих стандартов особенно важно в крупных проектах и при разработке компонентов для повторного использования.