Что такое анонимные классы в PHP?

Ответ

Анонимные классы в PHP — это классы, объявляемые и инстанцируемые одновременно, без явного объявления имени. Они полезны для создания одноразовых объектов, особенно в тестах или для реализации простых интерфейсов на лету.

Основные особенности:

  • Отсутствие имени: Доступны только через переменную, в которую был присвоен объект.
  • Конструктор: Могут принимать аргументы.
  • Наследование и реализация интерфейсов: Могут наследоваться от другого класса (extends) и/или реализовывать интерфейсы (implements).
  • Область видимости: Поддерживают все модификаторы доступа (public, protected, private).

Пример создания с аргументом и реализацией интерфейса:

interface LoggerInterface {
    public function log(string $message): void;
}

$logger = new class('app.log') implements LoggerInterface {
    public function __construct(private string $logFile) {}

    public function log(string $message): void {
        file_put_contents($this->logFile, $message . PHP_EOL, FILE_APPEND);
    }
};

$logger->log('Событие запуска');

Пример для тестирования (мок-объект):

// Вместо создания полноценного мок-класса
$mockService = new class extends SomeService {
    public function process(): bool {
        return true; // Заглушка для теста
    }
};

Их стоит использовать умеренно, так как чрезмерное применение может усложнить чтение кода и навигацию по нему.

Ответ 18+ 🔞

Ну и зачем они вообще нужны, эти анонимные классы? Представь ситуацию: тебе срочно нужен одноразовый объект, который нахуй никому не упёрся, кроме как прямо здесь и сейчас. Вот для этого они и существуют. Это как взять и на коленке собрать какую-то хрень, которая реализует интерфейс или наследуется от чего-то, но имя ей давать — только память тратить. Ёпта, удобно же!

Чем они примечательны, блядь:

  • Имени нет, сука: Поймал объект в переменную — и всё, обращаться больше не к чему. Как призрак, хуй с горы — появился, сделал дело и растворился.
  • Конструктор есть: Можешь сразу в него что-то запихнуть при создании.
  • Наследоваться и интерфейсы реализовать могут: Да-да, эта мартышлюшка может быть вполне себе законным наследником какого-нибудь родительского класса или честно выполнять контракт интерфейса.
  • public, private — всё как у людей: Никаких подвохов с областью видимости.

Смотри, как это выглядит на практике. Вот тебе логгер на скорую руку:

interface LoggerInterface {
    public function log(string $message): void;
}

$logger = new class('app.log') implements LoggerInterface {
    public function __construct(private string $logFile) {}

    public function log(string $message): void {
        file_put_contents($this->logFile, $message . PHP_EOL, FILE_APPEND);
    }
};

$logger->log('Событие запуска');

Видишь? Объявили интерфейс, а потом сразу, не отходя от кассы, создали объект, который его реализует. Аргумент в конструктор передали, свойство приватное объявили — красота!

Или вот классика — тесты, блядь. Не городить же отдельный класс-заглушку, который больше нигде не понадобится.

// Вместо создания полноценного мок-класса
$mockService = new class extends SomeService {
    public function process(): bool {
        return true; // Заглушка для теста
    }
};

Быстро, удобно, доверия ебать ноль к такому объекту в продакшене, но для теста — то, что надо.

Главное — не увлекаться ими, как дурак. Если натыкать их овердохуища по всему коду, то через месяц сам не разберёшь, что эта хитрая жопа делает и откуда взялась. Используй точечно, где реально упрощает жизнь, а не там, где просто лень нормальный класс написать.