зачем нужны интерфейсы php
Готовимся к собеседованию по PHP: Всё, что вы хотели узнать об интерфейсах, совместимости сигнатур и не побоялись узнать
Интерфейсы, впервые появившись в PHP 5, давно уже заняли прочное место в объектно-ориентированной (или всё-таки правильнее «класс-ориентированной»?) части языка.
Казалось бы — что может быть проще интерфейса? «Как бы класс, но и не класс, нельзя создать экземпляр, скорее контракт для будущих классов, содержит в себе заголовки публичных методов» — не правда ли, именно такими словами вы чаще всего отвечаете на собеседовании на дежурный вопрос о том, что такое интерфейс?
Однако не всё так просто, как может показаться начинающему программисту на PHP. Привычные аналогии не работают, руководство по языку вводит вас в заблуждение, в коде таятся неожиданные «подводные камни»…
Три предыдущие части:
Что может содержать интерфейс?
Очевидно, что публичные методы, причем без реализации: сразу после заголовка (сигнатуры) метода следует закончить его точкой с запятой:
Чуть менее очевиден (хотя и описан в мануале) тот факт, что интерфейс может содержать константы (разумеется, только публичные!):
Почему же константы в интерфейсах не получили широкого распространения в промышленном коде, хотя и используются иногда? Причина в том, что их невозможно переопределить в интерфейсе-наследнике или в классе, реализующем данный интерфейс. Константы интерфейсов — самые константные константы в мире 🙂
Чего не может содержать интерфейс?
Больше ничего не может. Кроме заголовков публичных методов и публичных констант.
Нельзя включать в интерфейс:
Совместимость сигнатур методов
Для дальнейшего изучения интерфейсов нам с вами нужно узнать о важнейшем понятии, которое незаслуженно обойдено вниманием в мануале по PHP: о понятии «совместимости сигнатур».
Сигнатура — это описание функции (метода), включающее в себя:
Предположим, что у нас есть две функции, A и B.
Сигнатура функции B считается совместимой с A (порядок важен, отношение несимметрично!) в строгом смысле, если:
Они полностью совпадают
Тривиальный случай, комментировать тут нечего.
B добавляет к A аргументы по умолчанию
B сужает область значений A
Теперь, когда мы ввели эти три простых правила совместимости определений, станет гораздо проще понять дальнейшие тонкости, связанные с интерфейсами.
Наследование интерфейсов
Интерфейсы могут наследоваться друг от друга:
Интерфейс-наследник получает от интерфейса-предка в наследство все определенные в предке методы и константы.
В интерфейсе-наследнике можно переопределить метод из родительского интерфейса. Но только при условии, что либо его сигнатура будет в точности совпадать с сигнатурой родительского, либо будет совместима (см. предыдущий раздел):
Если ли в PHP множественное наследование?
Если вам зададут такой вопрос, смело отвечайте: «да». Интерфейс может наследоваться от нескольких других интерфейсов.
Теперь вы видели всё:
Правила решения конфликтов сигнатур методов при множественном наследовании точно такие же, как мы уже видели выше:
— либо сигнатуры совпадают полностью
— либо сигнатура метода интерфейса, упомянутого в списке предков первым, должна быть совместима с сигнатурой из второго предка (да, порядок упоминания имеет значение, но это очень редкий кейс, просто не принимайте его никогда во внимание)
Тонкости реализации интерфейсов
Собственно, после всего, что вы уже видели, это уже и не тонкости, а так, мелкие нюансы.
Во-первых действительно, наследование класса от интерфейса называется реализацией. Смысл в том, что вы не просто получаете в наследство методы и константы, но обязаны реализовать те методы, которые заданы сигнатурами, наполнить их кодом:
Важный аспект, который отличает реализацию интерфейса от наследования от другого класса — это возможность реализовать в одном классе несколько интерфейсов сразу.
Как быть, если в разных интерфейсах, которые реализует класс, будет один и тот же метод (с одинаковым названием)? Смотри выше — также, как и при наследовании интерфейсов друг от друга должен соблюдаться принцип совместимости сигнатур.
И да. Не верьте мануалу, который провозглашает:
Сигнатуры методов в классе, реализующем интерфейс, должны точно совпадать с сигнатурами, используемыми в интерфейсе, в противном случае будет вызвана фатальная ошибка.
The class implementing the interface must use the exact same method signatures as are defined in the interface. Not doing so will result in a fatal error.
Всё не так, действует тоже самое правило совместимости:
Интерфейс — это класс? Pro et Contra
Вообще-то нет. Интерфейс — это интерфейс, он отличается от класса хотя бы тем, что нельзя создать «экземпляр интерфейса».
И вообще-то да, у них в PHP очень много общего:
Что почитать в ночь перед ответственным собеседованием?
Разумеется, мануал по языку:
Системный подход к самообразованию в программировании очень важен. И, по моему мнению, неплохо в начале пути в IT помогают структурировать самообучение вебинары и краткосрочные курсы. Именно поэтому я рекомендую (и немного скромно рекламирую) даже опытным разработчикам посещать разовые вебинары и курсы повышения квалификации — результат при грамотном сочетании курсов и самоподготовки всегда налицо!
Зачем нужны интерфейсы?
Друзья, неоднократно задавался вопросом и задавал вопрос здесь, беспокоит и не даёт покоя мысль о том, зачем нужны интерфейсы в php на пример.
Есть кучи примеров, где объяснятся лишь только то что, они задают жёстко типизированную структуру для других классов которые имплементируют и обязаны реализовывать публичные методы, но толку, неужели профит только в этом, бороздя статьи по интерфейсам были такие мнения что они позволяют обойти НЕмножественное наследование, то есть как? Объясните пожалуйста, элементарный пример связи, как это происходит?
Допустим есть интерфейс с одним методом. Имплементирующие его классы реализуют его под свои нужды как им хотелось бы, но везде по разному, и это всё? Допустим наследовались от того класса, который имплементировал интерфейс, дальше что?
Вернёт соответствующие строки, это и есть пример реализации интерфесов?
2 ответа 2
С интерфейсами можно решать много различных проблем в тех языках, где нет утиной типизации.
Всё ещё ищете ответ? Посмотрите другие вопросы с метками php интерфейс или задайте свой вопрос.
Связанные
Похожие
Подписаться на ленту
Для подписки на ленту скопируйте и вставьте эту ссылку в вашу программу для чтения RSS.
дизайн сайта / логотип © 2021 Stack Exchange Inc; материалы пользователей предоставляются на условиях лицензии cc by-sa. rev 2021.11.12.40742
Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.
Для чего нужны интерфейсы в PHP.
В этой заметке, постараюсь, кратко, объяснить в каких случаях стоит использовать интерфейсы в PHP и привести пример практического их использования.
Для начала, давайте рассмотрим пример без использования интерфейса.
Вот в таких случаях и используются интерфейсы. Они помогают в создании шаблонов для классов, которые будут использоваться в приложении и иметь общие методы делающие одни и те же задачи, но своим способом. Интерфейсы позволяют быстрее разобраться в коде и легче его поддерживать. Так же, они помогают создавать слабую связанность между классами, что можно продемонстрировать на примере:
В моем упрощенном примере видно, что интерфейс обязует реализующие его классы иметь метод insert(), который (допустим) непосредственно занимаются вставкой данных. А кроме него, каждый класс может иметь другие необходимые для его работы методы. Для класса saveDb, это, например, метод connectDb(), создающий соединение с базой данных. Для тестирования, я сделал вывод сообщений при срабатывании метода insert().
Таким образом, при работе с данными, в конструктор нужного класса или другой метод, мы можем передавать класс-сервис, указывая, что он относится к определенному интерфейсу и быть уверенными, что для всех классов данной группы используются одинаковые методы. Информацию про данные методы (документацию), кстати, можно указать прямо в коде интерфейса возле соответствующих методов, тем более, что там будет намного меньше строк чем в реализующих его классах.
В данном примере, вместо зависимости от конкретного класса (saveDb) передается зависимость от интерфейса Save:
Код класса Date не зависит от конкретного реализатора, а только от интерфейса. Стоит отметить, что данный пример построен на базе паттерна «Dependency injection», что переводится как «внедрение зависимости».
Интерфейс обеспечивает наличие указанных в нем методов во всех классах которые его реализуют. Поэтому можно быть уверенным, что вызов метода insert():
приведет к сохранению данных. При этом место хранения зависит от реализации данного метода в каждом из классов. Так, метод insert() класса saveDb сохраняет в базу данных, метод insert() класса saveFile сохраняет в файл и тд. Выполните код данного примера и увидите, что класс Date отработал со всеми классами интерфейса Save и при этом, код самого класса Date никак не пришлось менять.
Зачем нужны интерфейсы php
Интерфейсы объектов позволяют создавать код, который указывает, какие методы должен реализовать класс, без необходимости определять, как именно они должны быть реализованы. Интерфейсы разделяют пространство имён с классами и трейтами, поэтому они не могут называться одинаково.
Все методы, определённые в интерфейсах, должны быть общедоступными, что следует из самой природы интерфейса.
На практике интерфейсы используются в двух взаимодополняющих случаях:
Интерфейсы могут определять магические методы, требуя от реализующих классов реализации этих методов.
Хотя они поддерживаются, использование конструкторов в интерфейсах настоятельно не рекомендуется. Это значительно снижает гибкость объекта, реализующего интерфейс. Кроме того, к конструкторам не применяются правила наследования, что может привести к противоречивому и неожиданному поведению.
implements
Класс может реализовать два интерфейса, которые определяют метод с тем же именем, только если объявление метода в обоих интерфейсах идентично.
Класс, реализующий интерфейс, может использовать для своих параметров имя, отличное от имени интерфейса. Однако, начиная с PHP 8.0, в языке поддерживаются именованные аргументы, и вызывающий код может полагаться на имя параметра в интерфейсе. По этой причине настоятельно рекомендуется, чтобы разработчики использовали те же имена параметров, что и реализуемый интерфейс.
Интерфейсы могут быть унаследованы друг от друга, так же, как и классы, с помощью оператора extends.
Класс, реализующий интерфейс, должен объявить все методы в интерфейсе с совместимой сигнатурой.
Константы ( Constants )
Интерфейсы могут содержать константы. Константы интерфейсов работают точно так же, как и константы классов, за исключением того, что они не могут быть переопределены наследующим классом или интерфейсом.
Примеры
Пример #1 Пример интерфейса
Пример #2 Наследование интерфейсов
interface A
<
public function foo ();
>
// Это сработает
class C implements B
<
public function foo ()
<
>
// Это не сработает и выдаст фатальную ошибку
class D implements B
<
public function foo ()
<
>
Пример #3 Множественное наследование интерфейсов
interface A
<
public function foo ();
>
interface B
<
public function bar ();
>
class D implements C
<
public function foo ()
<
>
public function bar ()
<
>
Пример #4 Интерфейсы с константами
interface A
<
const B = ‘Константа интерфейса’ ;
>
// Выведет: Константа интерфейса
echo A :: B ;
// Это, однако, не будет работать, так как
// константы переопределять нельзя.
class B implements A
<
const B = ‘Константа класса’ ;
>
?>
Пример #5 Интерфейсы с абстрактными классами
Пример #6 Одновременное расширение и внедрение
Интерфейс, совместно с объявлениями типов, предоставляет отличный способ проверки того, что определённый объект содержит определённый набор методов. Смотрите также оператор instanceof и объявление типов.
Зачем нужны абстрактные классы и интерфейсы в php?
Простой 15 комментариев
Абстрактный класс- это реальные инструменты, необходимые для
1) повышения Читабельности кода
2) Уверенности в том, что делает код
Далее уже сделать имплементацию этого интерфейса на всех наследниках класса Tariff где нужно, и не парится, что через какое-то время другой разработчик создаст новую реализацию тарифа и с твоего кода посыпятся баги
Да, носят чисто декларативный характер
Ruslan Ruslanov, не для упрощения кода, а для стандартизации взаимодействия между объектами. Если на вашем компе есть юсб вход, то и мышка вам нужна с таким же интерфейсом. В данном случае юсб это стандарт для ваших объектов, соблюдая который вы можете взаимодействовать их.
Попробуйте написать классы для этого примера.
С интерфейсами самый простой кейс:
1) Пишем какую-то функцию, которая принимает в качестве аргумент интерфейс.
2) Функция работает с методами интерфейса и получает какой-то результат.
3) Где-то есть отдельная логика, выбора конкретной реализации класса, который выполняет интерфейс.
Т.е. допустим, у нас есть онлайн-касса и есть 20 методов платежей. Сама онлайн-касса работает с интерфейсом проводки платежа, а как проводить платежи реализовано в конкретных классах платежных систем.
Из минусов, иногда приходиться весьма «изящно» натягивать вещи, которые не очень ложатся на методы интерфейса, чтобы доп-функциональность работала согласно «верному пути» архитектора.
Абстрактный класс. ну допустим, мы далем абстрактный класс DTO, который выполняет методы to_string и normalize. Наследуюясь от этого абстрактного класса, мы во всех DTO получаем методы to_string и normalize. Плюс защищаемся от того, что кто-то решит нам запороать этот абстрактный класс, либо «решит» что-то сломать в своем DTO
Ну вообще, это все нужно, если ты пишешь хороший проект на Symfony командой. Если это какой-то бложит или небольшой новостник, тебе это все не нужно.
Абстрактные классы в основном используются в том случае, если какую-то часть кода можно описать в родительском классе, но для того чтоб эта часть приобрела смысл, нужна конкретика: дополнить общую картину подробностями в виде методов или полей. Если вы присмотритесь к абстрактным классам в современных фреймворках, то увидите что сам по себе абстрактный класс не имеет смысла. Например, если создать объект такого класса оператором new, то этому объекту всё равно будет чего-то не хватать и именно это что-то и добавляют дочерние классы.
> и в этом случае интерпретатор будет знать как перебрать коллекцию в цикле foreach.
Я бы сказал, что, как раз знать как перебрать он не будет, но сможет, тем не менее, заставить её перебраться. 🙂 Это немного тонкая разница, но тем не менее.
1. Абстрактный класс нельзя создать, только создать обьект от наследуемого класса
2. Абстрактный класс может содержать реализацию, в отличии от интерфейса
3. Абстрактный класс может содержать абстрактные методы, которые необходимо будет реализовать в дочерних классах
4. Можно имплементировать сразу несколько интерфейсов, а наследовать только от одного класса.
5. Трейты очень хорошо комбинируются с интерфейсами
Осознание зачем это нужно, прийдёт к вам в процессе использования)) Почитайте также про SOLID, и попробуйте реализовать эти принципы без абстракций и интерфейсов)
P.S. Домашнее задание
Есть три класса. Квадрат, Прямоугольник, Круг. И класс Ящик. Мы добавляем в ящик, произвольные наборы из фигур, и нужно посчитать площадь всех фигур в ящике.
Ruslan Ruslanov, Зачем указывать квадрату две стороны? Это же квадрат, у него стороны равны
Плюс врывается обезумевший заказчик, и хочет добавить треугольник, а также возможность задавать цвет, но только для круга и квадрата
P.S. Домашнее задание
Есть три класса. Квадрат, Прямоугольник, Круг. И класс Ящик. Мы добавляем в ящик, произвольные наборы из фигур, и нужно посчитать площадь всех фигур в ящике.
))) Я вас удивлю, но условия в жизни меняются чаще чем хотелось бы, и не всегда они меняются на те что ожидалось или хотелось. Для этого люди и придумывают разные практики и методики. Чтоб при очередном таком изменении, минимально переписывать код. А дальше уже каждый ищет для своей задачи эту золотую середину. Я считаю что нужно знать как можно больше подходов, чтоб выбрать оптимальный.
Вот рекомендую это изучить, а как поймете, о чём речь и для чего это всё. Тогда можно уже смело отбрасывать всё и делать как хочется)
https://ota-solid.now.sh/
P.S. В любом случае, это очень часто спрашивают на собеседованиях, так что если ваши планы более грандиозны, чем маленький самописный проект, который вы сами разрабатываете и не меняете в нём ничего, то стоит подготовится
но тогда просто будет сложно работать.
он (абстрактный класс) носит чисто декоративный характер, нужен для ограничения действий разработчика, удобства разработки и вообще это лишь «сахар?.