За последние 24 часа нас посетили 22947 программистов и 1241 робот. Сейчас ищут 764 программиста ...

Абстрактные методы и метод __call

Тема в разделе "PHP для профи", создана пользователем Argentum, 22 мар 2019.

  1. Argentum

    Argentum Активный пользователь

    С нами с:
    31 окт 2007
    Сообщения:
    24
    Симпатии:
    0
    Адрес:
    Москва
    Привет, All!
    Столкнулся со следующей проблемой.
    У меня есть класс - наследник абстрактного класса. В этом качестве он должен реализовывать все методы своего родителя. Но есть нюанс. Роль этого конкретного потомка - интерфейс. Все методы и данные он пропускает сквозь себя, спуская нижестоящим классам. Поэтому вместо того, чтобы морочиться с написанием кучи однотипных методов (чья задача - просто вызывать тот или иной нижестоящий класс), я написал вот такое:

    Код (Text):
    1. public function __call($name, $arguments)
    2. {
    3.     $result = call_user_func(array($this->main, $name), $arguments);
    4.     if ($result === FALSE)
    5.     {
    6.         $result = call_user_func(array($this->reserved, $name), $arguments);
    7.     }
    8.     return $result;
    9. }
    То бишь, вызов любого метода этого класса означает такой же вызов в нижестоящем классе (main), а если итог этого вызова неудовлетворительный, - то в резервном нижестоящем классе (reserved).

    При попытке выполнить этот код получаю ошибку типа:
    Код (Text):
    1. Fatal error: Class $foo contains abstract methods and must therefore be declared abstract or implement the remaining methods...
    То есть, несмотря на наличие магического метода __call, от меня требуют реализовать в потомке все абстрактные методы родителя.
    Можно ли как-то это обойти?
    Или я совершил архитектурную ошибку и делаю что-то не то?
     
  2. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.555
    Симпатии:
    1.754
    Не объявлять абстрактные методы...

    И почитай, когда вызывается __call, если метод объявлен в классе, не важно, абстрактным или нет, то __call не вызывается.
    --- Добавлено ---
    Для таких вещей, вообще, есть трейты (хотя их и не любят поборники чистого ООП).
     
  3. Valick

    Valick Активный пользователь

    С нами с:
    12 авг 2018
    Сообщения:
    1.911
    Симпатии:
    328
    @mkramer, а ты не любишь поборников? :)
    Для чистого ООП есть таки очень веская причина.
     
  4. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.555
    Симпатии:
    1.754
    @Valick, всё относительно. Один задачи прекрасно решаются обращением к ActiveRecord прямо в контроллере, а для других нужно городить огороды всяких декораторов, композитов и прочего. Чем сложнее задача, тем чище ООП. Моё мнение - надо знать, как правильно, и знать, что "делаю неправильно, но тут решается тремя строчками, посему сойдёт"
    --- Добавлено ---
    Лично я трейты пользую. Ну и то, что Laravel - это трейт на трейте и трейтом погоняет, говорит о том, что не один я не вижу в них ничего плохого.