Встроенные атрибуты PHP
PHP включает несколько атрибутов из коробки. Они обрабатываются самим движком и не требуют чтения через Reflection -- PHP реагирует на них автоматически.
#[Override] -- PHP 8.3+
Атрибут #[Override] на методе гарантирует, что метод действительно переопределяет родительский метод или реализует метод интерфейса. Если родительский метод не существует -- PHP выдаст ошибку.
<?php
declare(strict_types=1);
class Base
{
public function render(): string
{
return '';
}
public function process(): void
{
// business logic
}
}
class Child extends Base
{
// Корректно: метод существует в родителе
#[Override]
public function render(): string
{
return '<div>child content</div>';
}
// Fatal Error: Child::rendr() has #[Override] attribute,
// but no matching parent method exists
// #[Override]
// public function rendr(): string
// {
// return 'typo in method name!';
// }
}
Зачем нужен #[Override]:
- Защита от опечаток -- если имя метода не совпадает с родительским, сразу ошибка
- Защита от рефакторинга -- если родительский метод переименовали или удалили, все дочерние классы с
#[Override]сломаются с понятной ошибкой - Документирование намерения -- явно показывает, что метод переопределяет родительский
Работает с интерфейсами:
<?php
declare(strict_types=1);
interface Renderable
{
public function render(): string;
}
class Component implements Renderable
{
#[Override]
public function render(): string
{
return '<component />';
}
}
Работает с трейтами:
<?php
declare(strict_types=1);
trait Timestampable
{
public function getCreatedAt(): \DateTimeImmutable
{
return $this->createdAt;
}
}
class Article
{
use Timestampable;
private \DateTimeImmutable $createdAt;
// Переопределение метода из трейта
#[Override]
public function getCreatedAt(): \DateTimeImmutable
{
return $this->createdAt->setTimezone(new \DateTimeZone('UTC'));
}
}
PHP 8.5+: #[Override] также будет работать на свойствах, переопределяющих свойства из родительского класса или интерфейса (property hooks, abstract properties).
Рекомендация: Ставьте
#[Override]на каждый переопределённый метод. Это спасает от тихих багов при рефакторинге родительских классов.
#[Deprecated] -- PHP 8.4+
Атрибут #[Deprecated] помечает элемент как устаревший. При использовании такого элемента PHP генерирует предупреждение E_USER_DEPRECATED.
<?php
declare(strict_types=1);
// На функции
#[Deprecated("Use calculateTotal() instead", since: "2.0")]
function calculateSum(float $a, float $b): float
{
return $a + $b;
}
calculateSum(1, 2);
// Deprecated: Function calculateSum() is deprecated since 2.0,
// use calculateTotal() instead
// На методе
class PaymentService
{
#[Deprecated("Use processPayment() instead", since: "3.1")]
public function pay(float $amount): bool
{
return $this->processPayment($amount);
}
public function processPayment(float $amount): bool
{
// new implementation
return true;
}
}
// На константе класса
class Config
{
#[Deprecated("Use DB_HOST instead")]
public const DATABASE_HOST = 'localhost';
public const DB_HOST = 'localhost';
}
echo Config::DATABASE_HOST;
// Deprecated: Constant Config::DATABASE_HOST is deprecated,
// use DB_HOST instead
Параметры атрибута:
message(первый аргумент) -- текст предупреждения, подсказка что использовать вместоsince-- версия, с которой элемент устарел
Отличие от trigger_error:
<?php
declare(strict_types=1);
// До PHP 8.4 -- ручное предупреждение
function oldWay(): void
{
trigger_error('Use newWay() instead', E_USER_DEPRECATED);
}
// PHP 8.4+ -- нативный атрибут
#[Deprecated("Use newWay() instead", since: "2.0")]
function oldWayNative(): void
{
// code
}
Преимущества #[Deprecated] перед trigger_error:
- Срабатывает при вызове, а не при выполнении тела функции
- Информация доступна через Reflection и статический анализ
- IDE может подсвечивать вызовы устаревших функций
- Стандартный формат сообщения
PHP 8.5+: #[Deprecated] также будет доступен на трейтах и константах трейтов.
Запомни:
#[Deprecated]работает только на функциях, методах и константах классов. На классы, свойства и параметры -- не применяется (для классов используйте PHPDoc@deprecated).
#[SensitiveParameter] -- PHP 8.2+
Атрибут #[SensitiveParameter] скрывает значение параметра в стектрейсах и отладочной информации. Критически важен для безопасности:
<?php
declare(strict_types=1);
function authenticate(
string $username,
#[SensitiveParameter] string $password,
#[SensitiveParameter] string $apiKey,
): bool {
throw new \RuntimeException('Auth failed');
}
try {
authenticate('admin', 'super_secret_123', 'sk-abc123xyz');
} catch (\RuntimeException $e) {
echo $e->getTraceAsString();
}
// В стектрейсе:
// authenticate('admin', Object(SensitiveParameterValue), Object(SensitiveParameterValue))
// Пароль и API-ключ скрыты!
Без #[SensitiveParameter] пароли и токены могли бы попасть:
- В логи при uncaught exceptions
- В отчеты об ошибках (Sentry, Bugsnag)
- В дампы
var_dump($exception->getTrace())
Где применять:
<?php
declare(strict_types=1);
class DatabaseConnection
{
public function __construct(
private readonly string $host,
private readonly string $database,
private readonly string $user,
#[SensitiveParameter] private readonly string $password,
) {}
}
class EncryptionService
{
public function encrypt(
string $data,
#[SensitiveParameter] string $key,
#[SensitiveParameter] string $iv,
): string {
return openssl_encrypt($data, 'aes-256-cbc', $key, 0, $iv);
}
}
class TokenService
{
public function verify(
#[SensitiveParameter] string $token,
): bool {
// verification logic
return true;
}
}
Важно: Всегда ставьте
#[SensitiveParameter]на параметры, содержащие: пароли, токены, API-ключи, секреты шифрования, персональные данные (номера карт, SSN). Это одна из самых полезных мер безопасности в PHP.
#[AllowDynamicProperties] -- PHP 8.2+
Начиная с PHP 8.2, динамические свойства (присвоение несуществующих свойств) генерируют предупреждение E_DEPRECATED. В PHP 9.0 они будут запрещены. Атрибут #[AllowDynamicProperties] возвращает старое поведение:
<?php
declare(strict_types=1);
// Без атрибута -- deprecated в PHP 8.2+
class Config
{
public string $host = 'localhost';
}
$config = new Config();
$config->port = 3306;
// Deprecated: Creation of dynamic property Config::$port is deprecated
// С атрибутом -- динамические свойства разрешены
#[AllowDynamicProperties]
class DynamicConfig
{
public string $host = 'localhost';
}
$config = new DynamicConfig();
$config->port = 3306; // OK, no warning
$config->debug = true; // OK
Когда используется:
- Миграция легаси-кода -- временное решение на период рефакторинга
- ORM/ActiveRecord -- объекты с динамическими полями из базы данных
- Объекты-обёртки -- generic containers, stdClass-подобные
<?php
declare(strict_types=1);
// stdClass уже имеет этот атрибут неявно
$obj = new \stdClass();
$obj->anything = 'works'; // всегда OK
// Классы с __get/__set не нуждаются в атрибуте
class MagicClass
{
private array $data = [];
public function __get(string $name): mixed
{
return $this->data[$name] ?? null;
}
public function __set(string $name, mixed $value): void
{
$this->data[$name] = $value;
}
}
$magic = new MagicClass();
$magic->foo = 'bar'; // OK: вызывается __set, не динамическое свойство
Рекомендация: Не используйте
#[AllowDynamicProperties]в новом коде. Вместо этого объявляйте свойства явно или используйте массив$dataс магическими методами. Этот атрибут -- инструмент миграции, а не решение.
#[ReturnTypeWillChange] -- PHP 8.1+
Подавляет предупреждение E_DEPRECATED о несовпадении return type при реализации встроенных интерфейсов PHP:
<?php
declare(strict_types=1);
// PHP 8.1+ генерирует E_DEPRECATED, если встроенный метод
// не имеет return type, совместимого с интерфейсом
class MyCollection implements \Countable, \ArrayAccess
{
private array $items = [];
// Без атрибута: Deprecated: MyCollection::count(): Return type
// should either be compatible with Countable::count(): int,
// or the #[ReturnTypeWillChange] attribute should be used
#[ReturnTypeWillChange]
public function count() // намеренно без : int
{
return count($this->items);
}
// Лучше -- просто добавить return type:
public function offsetExists(mixed $offset): bool
{
return isset($this->items[$offset]);
}
#[ReturnTypeWillChange]
public function offsetGet(mixed $offset)
{
return $this->items[$offset] ?? null;
}
public function offsetSet(mixed $offset, mixed $value): void
{
$this->items[$offset] = $value;
}
public function offsetUnset(mixed $offset): void
{
unset($this->items[$offset]);
}
}
Когда нужен:
- Библиотеки, поддерживающие несколько версий PHP (7.x + 8.x)
- Реализация встроенных интерфейсов (
Iterator,ArrayAccess,Countable,JsonSerializable) - Временная мера до добавления правильных return types
Рекомендация: В новом коде (PHP 8.1+) лучше добавить правильный return type вместо использования
#[ReturnTypeWillChange]. Этот атрибут предназначен для обратной совместимости.
#[NoDiscard] -- PHP 8.5+
Атрибут #[NoDiscard] предупреждает, когда возвращаемое значение функции игнорируется. Это помогает предотвратить баги, когда разработчик забыл обработать результат:
<?php
declare(strict_types=1);
#[NoDiscard("Validate result must be checked")]
function validate(mixed $data): ValidationResult
{
// validation logic
return new ValidationResult(isValid: false, errors: ['Invalid data']);
}
// Warning: The return value of function validate() is expected
// to be consumed, Validate result must be checked
validate($input); // Результат проигнорирован!
// Правильно: проверяем результат
$result = validate($input);
if (!$result->isValid) {
throw new ValidationException($result->errors);
}
Подавление предупреждения через (void):
<?php
declare(strict_types=1);
#[NoDiscard]
function importantResult(): bool
{
return true;
}
// Если вы осознанно игнорируете результат -- приведите к void
(void) importantResult(); // OK, no warning
Применение на классах и методах:
<?php
declare(strict_types=1);
// На классе -- все методы, возвращающие этот тип, будут проверяться
#[NoDiscard("Result object should not be ignored")]
final readonly class Result
{
public function __construct(
public bool $success,
public string $message = '',
) {}
}
class OrderService
{
// На конкретном методе
#[NoDiscard("Check if order was placed successfully")]
public function placeOrder(Order $order): Result
{
// process order
return new Result(success: true);
}
}
$service = new OrderService();
$service->placeOrder($order); // Warning! Result ignored
Типичные случаи для #[NoDiscard]:
- Функции валидации -- результат проверки нужно обработать
- Операции с побочными эффектами -- результат операции (успех/ошибка)
- Иммутабельные методы --
str_replace,array_filter-- результат всегда новый - Builder pattern -- каждый вызов возвращает новый объект
#[DelayedTargetValidation] -- PHP 8.5+
Этот мета-атрибут применяется к классам-атрибутам и откладывает проверку цели до момента вызова newInstance(). По умолчанию PHP проверяет цель при компиляции, что может вызывать проблемы для атрибутов, которые обрабатываются внешними инструментами.
<?php
declare(strict_types=1);
use Attribute;
// Стандартное поведение: цель проверяется при компиляции
#[Attribute(Attribute::TARGET_METHOD)]
final class StrictAttr {}
// С отложенной валидацией: цель проверяется при newInstance()
#[Attribute(Attribute::TARGET_METHOD)]
#[DelayedTargetValidation]
final class FlexibleAttr {}
// Для StrictAttr ошибка может возникнуть при компиляции
// Для FlexibleAttr ошибка возникнет только при явном чтении
Этот атрибут полезен для:
- Атрибутов в библиотеках, которые обрабатываются внешними инструментами (Doctrine, Symfony)
- Атрибутов, чья валидация требует загрузки зависимостей
- Кросс-фреймворковых атрибутов с нестандартным поведением
Сводная таблица встроенных атрибутов
| Атрибут | Версия PHP | Цель | Назначение |
|---|---|---|---|
#[Attribute] |
8.0+ | Классы | Мета-атрибут: объявление класса-атрибута |
#[ReturnTypeWillChange] |
8.1+ | Методы | Подавление deprecation notice для return type |
#[SensitiveParameter] |
8.2+ | Параметры | Скрытие значений в стектрейсах |
#[AllowDynamicProperties] |
8.2+ | Классы | Разрешение динамических свойств |
#[Override] |
8.3+ | Методы | Проверка переопределения родительского метода |
#[Deprecated] |
8.4+ | Функции, методы, константы | Пометка устаревшего кода |
#[NoDiscard] |
8.5+ | Функции, методы, классы | Предупреждение при игнорировании возвращаемого значения |
#[DelayedTargetValidation] |
8.5+ | Классы-атрибуты | Отложенная проверка цели атрибута |