В PHP отсутствует Double Dispatching и перегрузка методов
Double Dispatch в PHP:
class Foo {
// ...
public function makeSomeStuff(Bar $bar)
{
$bar->doStuff($this->someData); // double dispatch!
}
}
Перегрузка методов:
class Foo {
public function foo() {}
}
class Bar extends Foo {
public function foo() {} // перегружен!
}
и в ответ на отличающуюся от базового класса/интерфейса сигнатуру он вывалится с ошибкой
то что вы хотели сделать называется ad-hoc полиморфизм, и он есть из коробки в любом языке программирования с динамической типизацией. Достаточно просто не указывать явно сигнатуру, все довольно просто) Ну и да, минус этого то что это не явно и в рантайме. Для языков со статической типизацией явная "перегрузка" нужна только для того что бы компилятор мог построить таблицы диспетчеризации вызовов.
Но решить проблему как-то нужно
Перегрузка методов в наследниках с изменением сигнатуры это как раз таки нарушение принципа подстановки барбары лисков (LSP для сокращения).
> Сервисы должны имплементировать какие-то общие методы, но помимо этого у них есть и специфичные методы.
выносите "общие методы" в отдельный сервис и шарьте его как зависимость. Тогда у всех сервисов будут только специфичные методы и тогда будет достигаться принцип единой ответственности (который характеризуется как "у каждого объекта должна быть только одна причина для возможных изменений").
p.s. венгерская нотация - это ужас. Все эти префиксы и суффиксы которые показывают кто есть тип (интерфейс, абстрактный класс) это вещи которые ломают всю красоту идеи полиморфизма и абстракции. Если хотите можем об этом пообщаться отдельно.
Однако каждый из хендлеров может не работать с конкретной реализацией сервиса.
Значит полиморфизм в нашем случае пошел погулять. Есть куча решений данной проблемы, в частности Chain of responsibility.
> Visitor. Предполагает наличие в каждом из хендлеров методов типа handleService1(Service1 $service) и handleService2(Service2 $service), при этом один из методов остается пустым
зачем так усложнять то? У вас должен быть снаружи только один публичный метод а внутри уже реализация сама разберется. Ну то есть если хотите - можете внутри сделать два приватных метода но это так же странно.
> Массив маппинга, который говорит, какой хендлер может обрабатывать какой из сервисов.
Опять же излишнее усложнение.
Короче ваша проблема в том что у вас есть некие сервисы, с неким интерфейсом, которые по факту делают совсем разные вещи. То есть они априори не могут принадлежать к одному и тому же типу. Ну и нарушение LSP на лицо, вы не можете в коде заменить одну реализацию сервиса другой.
Дальнейшие варианты возможны только после того, как вы опишите на высоком уровне что вам нужно сделать. Ну то есть не то к чему вы пришли а почему вы к этому пришли и какая задача стояла изначально.