Можно ли в классе оставить два метода с одинаковым именем, но разной сигнатурой (перегрузка методов)?

«Можно ли в классе оставить два метода с одинаковым именем, но разной сигнатурой (перегрузка методов)?» — вопрос из категории ООП, который задают на 24% собеседований PHP Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Нет, в PHP нельзя иметь в одном классе несколько методов с одинаковым именем, даже если у них разные сигнатуры (количество или типы параметров). Попытка объявить такой метод вызовет фатальную ошибку Fatal error: Cannot redeclare ClassName::methodName().

PHP не поддерживает перегрузку методов (method overloading) в том виде, как это есть в Java или C#.

Обходные пути и решения:

  1. Использование аргументов по умолчанию и проверок внутри метода:

    class Processor {
        public function process($data, string $mode = 'default') {
            if (is_array($data)) {
                // Обработка массива
            } elseif (is_string($data)) {
                // Обработка строки
            }
            // Дополнительная логика в зависимости от $mode
        }
    }
  2. Использование магического метода __call() для динамической диспетчеризации:

    class DynamicHandler {
        public function __call($name, $arguments) {
            if ($name === 'handle') {
                if (count($arguments) === 1) {
                    return $this->handleSingle($arguments[0]);
                } elseif (count($arguments) === 2) {
                    return $this->handleDouble($arguments[0], $arguments[1]);
                }
            }
            trigger_error('Method not found', E_USER_ERROR);
        }
    
        private function handleSingle($arg) { /* ... */ }
        private function handleDouble($arg1, $arg2) { /* ... */ }
    }
  3. Разрешение конфликтов при использовании трейтов (если методы пришли из разных трейтов):

    trait FormatterA {
        public function format($data) { return json_encode($data); }
    }
    trait FormatterB {
        public function format($data) { return serialize($data); }
    }
    
    class MyClass {
        use FormatterA, FormatterB {
            FormatterA::format insteadof FormatterB; // Используем format из FormatterA
            FormatterB::format as formatSerialized;   // Переименовываем format из FormatterB
        }
    }