Атрибути (PHP 8.0) - структуровані метадані, прикріплені до класів, методів, властивостей, параметрів, функцій і констант. Синтаксис #[...]. На відміну від анотацій у PHPDoc, атрибути - частина мови: перевіряються синтаксично, мають класи й автодоповнення.
Оголошення атрибута:
#[Attribute(Attribute::TARGET_METHOD)]
final class Route
{
public function __construct(
public string $path,
public string $method = 'GET',
) {}
}
Використання:
final class UserController
{
#[Route('/users', method: 'GET')]
public function index(): Response { /* ... */ }
}
Читання через Reflection:
foreach ((new ReflectionClass(UserController::class))->getMethods() as $method) {
foreach ($method->getAttributes(Route::class) as $attribute) {
$route = $attribute->newInstance(); // створює об'єкт Route з аргументами
$router->add($route->method, $route->path, [$method->class, $method->name]);
}
}
Важливо: атрибут сам нічого не робить. Це лише дані, які хтось має прочитати. Об'єкт атрибута створюється лише при newInstance().
Вбудовані атрибути PHP: #[\Override] (8.3) - перевірка, що метод справді перевизначає батьківський; #[\SensitiveParameter] (8.2) - приховати значення параметра в стек-трейсах (паролі); #[\Deprecated] (8.4); #[\NoDiscard] (8.5) - попередження, якщо результат функції проігноровано; #[\AllowDynamicProperties].
У Laravel: атрибути контейнера (#[Config('app.name')], #[CurrentUser], #[Storage('s3')]), атрибути моделей (#[ObservedBy], #[ScopedBy]), атрибути Livewire (#[Url], #[Locked], #[Computed]).
Продуктивність: читання через Reflection не безкоштовне - фреймворки кешують результат (кеш маршрутів, скомпільований контейнер).