Можно ли добавить статический метод в интерфейс?

Ответ

Да, начиная с PHP 8.1, интерфейсы могут содержать статические методы. Это позволяет определить общий статический контракт для всех реализующих классов.

Пример:

interface Logger {
    public static function create(string $name): self;
    public function log(string $message): void;
}

class FileLogger implements Logger {
    private string $name;

    private function __construct(string $name) {
        $this->name = $name;
    }

    public static function create(string $name): self {
        return new self($name);
    }

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

// Использование
$logger = FileLogger::create('app');
$logger->log('Запуск системы');

Ключевые моменты:

  1. Статические методы в интерфейсах должны быть объявлены как public.
  2. Они не могут быть абстрактными (должны иметь тело, даже если это просто {} в интерфейсе).
  3. Класс, реализующий интерфейс, должен предоставить метод с точно такой же сигнатурой.
  4. До PHP 8.1 объявление статического метода в интерфейсе вызывало фатальную ошибку.

Ответ 18+ 🔞

А, ну вот это поворот, ёпта! Раньше-то в интерфейсах статику запихнуть было нельзя, аж до версии 8.1. А теперь — пожалуйста, нате вам. Теперь можно в интерфейсе прописать, что все, кто его реализует, обязаны иметь какой-то конкретный статический метод. Удобно, если вам нужен единый фабричный метод create() для всех логгеров или чего-то такого.

Смотри, как это выглядит:

interface Logger {
    public static function create(string $name): self;
    public function log(string $message): void;
}

class FileLogger implements Logger {
    private string $name;

    private function __construct(string $name) {
        $this->name = $name;
    }

    public static function create(string $name): self {
        return new self($name);
    }

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

// Использование
$logger = FileLogger::create('app');
$logger->log('Запуск системы');

А теперь главное, что надо запомнить, а то накосячишь:

  1. Эти статические методы в интерфейсе обязательно должны быть public. Никаких private static там не завезли, и слава богу, а то был бы пиздопроебибна.
  2. Они не могут быть абстрактными, им прямо в интерфейсе нужно тело писать. Пусть даже пустое — {}, но писать.
  3. Класс, который этот интерфейс подписывает, обязан этот статик метод реализовать, причём с точно такой же сигнатурой. Иначе — сам от себя охуеешь, когда компилятор тебе в рыло ошибку вывалит.
  4. И да, главное — раньше, до 8.1, если бы ты попробовал так сделать, PHP бы тебе просто сказал «иди ты нахуй» фатальной ошибкой. А теперь — можно. Прогресс, блядь, налицо.