Фабричный метод — это паттерн программирования, который используется для получения экземпляров объектов на основе некоторого заданного параметра. В своих PHP-проектах, я часто использую его. Но в других проектах, которые я вижу, многие фабричные классы весьма запутанны.
Пример
Допустим, у нас есть Фабрика, который будет создавать CarEngine на основе модели Car. Чаще всего я вижу такую реализацию:
class CarEngineFactory implements ICarEngineFactory
{
    public function make(string $carBrand): IEngine
    {
       switch ($carBrand) {
           case "mercedes":
              return new MercedesEngine();
           case "bmw":
               return new BmwEngine();
           default: 
                throw new CarEngineNotAvailableException();          
       }
    }
}
Выглядит вроде нормально, да? Ну, пока у нас есть только два варианта, то да. Но если мы будем добавлять все больше и больше марок автомобилей в нашу систему, этот фабрикой станет всё сложнее пользоваться.
Проблемы:
- Параметры — это просто случайные строки, поэтому разработчикам будет сложно разобраться, что нужно передавать.
- Чем больше марок автомобилей добавлено — тем больше будет блок switch.
Я вижу решение этого таким:
class CarEngineFactory implements ICarEngineFactory
{
    protected static $availableEngines = [
        Mercedes::class => MercedesEngine::class,
        Bmw::class => BmwEngine::class,
    ];
    public function make(ICar $car): IEngine
    {
        $carClass = get_class($car);
        if (!array_key_exists(get_class($car), self::$availableEngines)) {
            throw new CarEngineNotAvailableException();
        }
        $engineClass = self::$availableEngines[$carClass];
        return (new $engineClass());
    }
}
Теперь у нас есть статический массив с классами Car и CarEngine. Вместо рандомных строк мы передаем весь объект. И теперь, если мы хотим добавить еще одну марку Car с соответствующим CarEngine, то нам просто нужно описать это в $availableEngines, и готово!
Если у нас очень большой блок switch case, то использование array_key_exists будет намного быстрее, потому что эта команда выполняет поиск по хешу и работает почти во временной сложности O(1) (почти — из-за возможных коллизий хешей).
Этот метод предоставляем нам больше гибкости. Например, $availableEngines можно переместить в конфигурационный файл.
Разумеется, это просто базовая реализация фабричного метода. Фабрики могут быть гораздо сложнее, но главное, что я хотел показать в этом примере, это то, что мы не должны передавать в них рандомные непонятные строки. Это затрудняет их чтение и использование другими разработчиками, работающими над этим же проектом.
Автор: Georgi Razsolkov
Перевод: Алексей Широков
Наш  Телеграм-канал — следите за новостями о Laravel.

