Ответ
Аннотации в PHP (официально называемые атрибутами, attributes) — это форма метаданных, которая добавляется к классам, методам, свойствам или параметрам для предоставления дополнительной информации. Они были введены в PHP 8.0 и представляют собой структурированную альтернативу док-блокам с аннотациями.
Синтаксис и базовое использование:
// Объявление атрибута (класс атрибута)
#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)]
class Route {
public function __construct(
public string $path,
public array $methods = ['GET']
) {}
}
// Применение атрибута к классу и методу
#[Route('/api/users')]
class UserController {
#[Route('/{id}', methods: ['GET'])]
public function show(int $id): Response {
// ...
}
}
Как я использую атрибуты в реальных проектах:
-
Маршрутизация в фреймворках:
// Symfony с атрибутами #[Route('/api/products')] class ProductController { #[Route('/{id}', name: 'product_show', methods: ['GET'])] #[IsGranted('ROLE_USER')] public function show(Product $product): JsonResponse { return $this->json($product); } #[Route('', name: 'product_create', methods: ['POST'])] #[IsGranted('ROLE_ADMIN')] #[ValidateRequest] public function create(Request $request): JsonResponse { // ... } } -
Валидация данных:
class UserDto { #[AssertNotBlank] #[AssertLength(min: 3, max: 50)] public string $username; #[AssertNotBlank] #[AssertEmail] public string $email; #[AssertChoice(['male', 'female', 'other'])] public string $gender; #[AssertRange(min: 18, max: 100)] public int $age; } -
Маппинг Doctrine ORM:
#[Entity] #[Table(name: 'users')] class User { #[Id] #[GeneratedValue] #[Column(type: 'integer')] private ?int $id = null; #[Column(type: 'string', length: 180, unique: true)] private string $email; #[OneToMany(mappedBy: 'user', targetEntity: Order::class)] private Collection $orders; #[Column(type: 'datetime')] private DateTimeInterface $createdAt; public function __construct() { $this->createdAt = new DateTimeImmutable(); $this->orders = new ArrayCollection(); } } -
Кастомные атрибуты для логики приложения:
// Атрибут для кэширования результатов метода #[Attribute(Attribute::TARGET_METHOD)] class CacheResult { public function __construct( public int $ttl = 3600, public ?string $key = null ) {} } // Обработчик атрибута class CacheResultHandler { public function handle(object $object, string $method, array $args): mixed { $reflection = new ReflectionMethod($object, $method); $attributes = $reflection->getAttributes(CacheResult::class); if (empty($attributes)) { return $object->$method(...$args); } $cacheAttr = $attributes[0]->newInstance(); $cacheKey = $cacheAttr->key ?? $this->generateKey($object, $method, $args); if ($cached = Cache::get($cacheKey)) { return $cached; } $result = $object->$method(...$args); Cache::set($cacheKey, $result, $cacheAttr->ttl); return $result; } }
Преимущества перед док-блоками:
- Выполняемый код: Атрибуты — это реальные классы PHP, которые можно инстанциировать и использовать
- Проверка типов: IDE и статические анализаторы понимают типы параметров
- Автодополнение: PhpStorm подсказывает доступные параметры атрибутов
- Производительность: Не нужно парсить строки, как в случае с аннотациями в док-блоках
- Структурированные данные: Параметры атрибутов типизированы и валидируются
Чтение атрибутов через Reflection API:
$reflectionClass = new ReflectionClass(UserController::class);
$attributes = $reflectionClass->getAttributes(Route::class);
if (!empty($attributes)) {
$routeAttribute = $attributes[0]->newInstance();
echo "Path: " . $routeAttribute->path; // /api/users
}
Атрибуты значительно улучшили опыт работы с метаданными в PHP, сделав код более типобезопасным и удобным для анализа инструментами разработки.