PHP: интерфейсы и абстрактные классы
09.10.2010 технологии
О теме из заголовка, я надеюсь, грамотно и понятно напишут опытные крутые программисты в комментариях, потому что у меня понимания нет. Сегодня весь день читаю статьи про ООП и MVC, многое понял и узнал много нового, но с интерфейсами и абстрактными классами затык.
Зачем они нужны?
Я пришёл к выводу, что интерфейсы и абстрактные классы в PHP — это как просто соглашения, выраженные формально в коде. Но если это просто соглашения, зачем для них писать фактически пустой код? Непонятно. Объясните, пожалуйста. Было бы здорово, если бы показали примеры, когда интерфейсы и абстрактные классы действительно необходимы.
P.S. Сейчас ещё дочитаю кое-что и начну делать первый в жизни класс! :) Планирую сделать класс-обёртку API AvisoSMS для работы с короткими номерами. Код, естественно, отдам в открытый доступ, и надеюсь на его критику.
P.P.S. Если вы понимаете, зачем нужны интерфейсы и абстрактные классы, но вам лень объяснить или не умеете, киньте хотя бы разъясняющие ссылки в комментариях.
Комментарии
Комментирование этой статьи закрыто.
« Методы проектирования модульных систем Снова надо обновить Daos »
Так, ну ладно, абстрактный класс может содержать реальные какие-то элементы, так что с ним более-менее понятно, а вот с интерфейсами непонятно совсем.
Вообще тема очень обширна, не для комментариев одного поста. Холиваров много, разговоров. Тут смотря что тебе в программировании нравится и смотря каков твой стиль, твоя школа. Смотря что ты использовал ранее. Эти понятия в PHP пришли из более «старших» братьев, вот я небольшой примерчик набросал:
dumpz.org/22911/
Хотя он только частично объясняет зачем это нужно. Можешь поискать по форуму phpclub, когда-то я там зависал и познавал все эти истины, но на даном этапе я б тебе советовал почитать что-то по ООД, паттернам, до полного просветления :).
Хотя некоторые считают что все это «понты» и перегруз, и обычными функциями вполне себе так можно обойтись.
А вообще в гугле по запросу «зачем нужны интерфейсы в PHP» ответов более чем достаточно…
Может я тупой, но мне твои примеры ничего не разъяснили :) Зачем определять интерфейсы и потом их наследовать, если реализацию их методов всё равно делаешь отдельно внутри каждого класса?
В гугле искал перед созданием этой заметки, везде такая же вода, нет чётких мнений и прозрачных примеров, из которых становится ясно — да, интерфейсы нужны.
Если кратко – для того, чтобы код, который был написан ранее мог работать с классами, которые будут написаны в будущем.
В основном используют разработчики библиотек.
В качестве примера могу привести одну из своих статей – www.simplecoding.org….
Там используется фреймворк Yii. В нем есть интерфейс IUserIdentity, который должны реализовать все классы, выполняющие аутентификацию пользователей. За счет этого можно написать свой класс, который будет поддерживать новый метод аутентификации (именно это я и сделал). При этом все остальные компоненты фреймворка точно знают, что у нового класса есть методы authenticate, getId, getIsAuthenticated и т.д., и могут их вызывать.
В качестве аналога можно взять физические интерфейсы (USB, HDMI, …). Если бы каждый производитель делал их по-своему, то монитор от samsung можно было бы включить только в разъем samsung.
Тормоз, расскажу случай из моей жизни. Был у нас проект на Java на троих разработчиков. Чтоб долго не думать, разделились по MVC. Немного не поровну, но нам прокатило: самый «умный» взялся за Модель, второй за Контроллер, а я за Отображение. Ну про ООП и МВЦ я уже здесь писал так что повторяться не буду.
А вот интерфейсы нам пригодились так. Когда мы собрались вместе впервые, мы обдумали интерфейсы, в них описание кто какие классы и методы реализовывает. Дальше каждый писал код по отдельности, только свои классы, но в местах, где надо было использование классов напарника, использовались названия интерфейсных методов. За пару дней до сдачи проекта, мы собрались вместе и объединили всё в один проект, а интерфейсы были своеобразным «порталом» между моделью, контроллером и отображением. При этом каждый из нас углублялся в реализацию только своего класса, не задумываясь о том, как реализованы методы напарников.
Интрефейсы нужны для того, чтобы четко обозначить поведение объектов которые будут реализовывать эти интерфейсы. Например, когда делают
foreach ($Object as $element){}
$Object должен реализовывать интерфейс Iterator, от астрактных классов в php отличаются не только тем, что в абстрактных может быть логика, класс может реализовывать много интерфейсов, но наследуют не более одиного класса.
Интерфейсы имеют много положительных сторон, их применение вносить порядок в ООП. Если говорить с точки зрения теории – интерфейсы и абстрактные классы это инструменты для реализации полиморфизма.
Интерфейс – суть вырожденный абстрактный класс.
Вот основные известные мне причины, зачем он нужен:
1) Стандартизировать интерфейс модуля. Например, у тебя есть три платежных шлюза, к которым ты делаешь обертки для своего проекта. Чтобы работать со всеми универсально, ты определяешь интерфейс из всех нужных тебе функций, а потом реализуешь его в классе для каждого шлюза. При этом общего кода у них все равно нет, так что пользы от наследования от базового класса нет.
2) Это больше относится к языкам со строгой типизацией, в PHP это чисто формальность. Интерфейсы используют для логического разделения функционала класса на независимые части. И если какому-то методу нужен будет объект, реализующий интерфейс A, то передавая такой объект мы будем уверены, что метод знает только про нужный ему функционал и не может сделать с объектом ничего не предусмотренного интерфейсом А.
3) Реализацию нескольких интерфейсов в языке сделать чисто технически гораздо проще, чем множественное наследование классов при похожих целях использования. Почитай про множественное наследование в C++ и связанные с этим проблемы.
Ну и последнее, в одном из твоих старых постов, где ты спрашивал, как бы подучить ООП, я давал ссылку на нашу методичку, где все очень годно описано.
Я всё понял! Просто сделал тестовый интерфейс и класс, в котором должен этот интерфейс использоваться, но в классе не стал реализовывать декларируемый интерфейсом метод.
И PHP вернул ошибку «Fatal error: Class testIface contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (test::test) in /home/begemot/www/test/interfaces.php on line 17».
Ура! В голове прояснилось :) Интерфейсы прописываются именно кодом, а не свободным соглашением простым языком, чтобы интерпретатор проверял наличие интерфейсов и генерировал ошибку, если класс интерфейсы не реализует, как того от него требуют.
O_o
Ну да, это конечно можно заменить обычным соглашением, но тогда не будет валидации на этапе компиляции, не будет плюшек в ИДЕшках и прочего.. Хотя многие считают что и без них можно обойтись…
Миша, см. выше, я это уже как раз выяснил на практике :) Мне надо было сразу так сделать и не задавать глупых вопросов.
Смотри пример. Пишем модульную CMS. Обьявляем интерфейс модуля, в котором указывает что класс модуля должен реализовывать методы для вывода ссылки на модуль в меню, для вывода помощи в меню, метод установки, деинсталляции модуля. И потом соответственно любой разработчик модуля смотрит на интерфейс, и реализовывает все, что необходимо для типичного модуля данной CMS. А уже разработчик ядра, например делаю какуюнить новую фичу, может свободно рассчитывать что каждый модуль например имеет метод getHelp() которыя выводит справку по модулю. Как то так.
От ты даёшь, сам в конце говоришь, что будешь писать обёртку — это ж и есть интерфейс.
Вообще — у тебя в ноуте есть USB, а на фотике — miniUSB. Без интерфейса, тьфу, провода-переходника тебе надо бурить дырку в стенке и распаивать на очень низком уровне всё. Это непрактично.
ЗЫ: про «лишний код» тож убил. ООП — это вообще бешенные проценты излишнего кода (в приложении к «сейчас», в приложении к «потом» он как раз нелишний).
Если кого мини-usb не возбудил — ок, пусть будет com-порт или какие-нить специфические звуковые выходы.
Molfar, про модульность, кстати, сейчас отдельно напишу, есть ещё мысли, которые недают покоя.
Samlowry, ты совсем ничего не понял. Я здесь пишу исключительно про интерфейсы в терминах PHP.
Нубский вопрос=) Я правильно понимаю, что MVC без ООП не имеет смысла? Пробовал заюзать MVC без ООП – ничего не получилось, те же инклуды, вид с боку) Пока забил на MVC, т. к. в ближайших планах учить ООП нет. Или может быть я просто не до конца MVC вкурил и можно без ООП обойтись?
Мне кажется, можно делать MVC без ООП, по крайней мере не вижу серьезных препятствий для реализации.
Только во всём нужна мера, применять те или иные подходы нужно когда они действительно необходимы, а не просто потому что модно или об этом говорят. Об этом недавно Евгений Сергеев неплохо написал.
Блият, похерился весь коммент. Короч, enjoy the moment и юзай бешенные плюсы документации PHP — структуированность и User Contributed Notes. Открываешь описание волнующего элемента языка — читаешь эти самые заметки. Они там 90% полезной информации несут от документации, все популярные вопросы разбираются там, да ещё и с кодом. Например, php.net/manual/en/la…
Как куда шаг делаю от PHP (что угодно — perl, python, mysql, какие-нить мелкие либы) — страдаю прям, что документация на порядки хуже, и вся полезная инфа размазана.
Читаю иногда, но мне русский язык пока воспринимать гораздо проще, на разбор английского текста я трачу гораздо больше времени.
2tulvit: ООП и MVC между собой никак не связанны. Реализовать MVC без ООП легко, также, как и использовать ООП без MVC ;). Тут все зависит в кривизне рук конкретного программиста.
Вот простой пример MVC без ООП: предположим, есть урл site.com/db/load/1, который приходит на index.php. Скрипт, разбирает урл и подключает нужную «модель» (db.php или file.php, например. в данном случае – db.php), потом вызывает функцию load с параметром «1»… Результат передает в функцию view (может находится как в index.php, так и в отдельном файле), которая формирует страницу. Все.
Интерфейс – протокол (набор соглашений и правил).
Класс – конкретная реализация правил и соглашений.
Интерфейсы – общие, классы – конкретные реализации.
Интерфейсы позволяют создавать слабосвязанные системы (модульность, гибкость, масштабирование, выбор архитектуры).
Model – бизнес логика, доступ к данным.
View – представление данных в нужном виде.
Controller – интерактивное взаимодействие между пользователем и интернет сайтом.
/Home/Index/
контроллер дом показать индекс
/MyController/MyAction/MyParameter
ООП – парадигма программирования.
MVC – шаблон проектирования.
Это разные вещи. Могут существовать раздельно.
Если вызвать метод не описанный в классе, то интерпертеторо всё равно вернёт ошибку разбора:
Parse error: syntax error, unexpected T_VARIABLE, expecting T_FUNCTION in /www/test.local/www/obj.php on line 11
Для того что бы определять является ли объект экземпляром определенного класса, можно ведь использовать instanceof.
Для того что бы обьект содержал в себе какие-то необходимые методы то лучше создать главный, абстрактный класс и в нём описать всё что нужно.
Интерфейсы в php по моему мнению бесполезны как и обстрактные классы или у меня тоже нет понимания.