«phpClub» — архив тем ("тредов"), посвящённых изучению PHP и веб-технологий.
Аноним 2019/01/21 09:53:28  №1331602 1
До сих пор не совсем понимаю нужду в интерфейсах и абстрактных классах.
Может кто oбъяснить на примерах?

Это просто как шаблон реализовав по которому класс, oн тoчнo будет верно работать?
Ответы: >>1331675
Аноним 2019/01/21 10:51:09  №1331675 2
>>1331602
Ну смотри, допустим у тебя в приложении есть форма логина, пишешь для нее класс.
Затем тебе понадобилась форма регистрации, пишешь для нее класс.
Тут замечаешь, что добрая половина методов и свойств первой и второй формы совпадает.
Если ты быдлокодер и тебе нaсрать на качество твой работы, ты так и оставишь, тем более что ты никогда не писал приложение с более чем 2-3 формами.
Но если ты ответственный программист, то догадываешься, что копипастить куски кода из одного класса в другой наверное неправильно. Тем более что в серьезных приложениях родственных классов будет не 2-3, а десятки-сотни.
Пишешь абстрактный класс, который содержит в себе все общее, что есть у классов форм, называешь AbstractForm.
Наследуешь LoginForm и RegisterForm от AbstractForm, в них прописываешь только уникальные для данного класса свойства и методы.

Что касается интерфейса, то это набор требований к классу, то есть буквально мы пишем: "у всех классов, которые имплементируют данный интерфейс, должен быть определенный функционал (метод), неважно как они будут реализованы, но они должны быть". Пример не знаю какой привести.
Вот чувак приводит пример со столами https://toster.ru/q/10682
>Связью же интерфейсов и классов Вы описываете свойства. Например, стол можно катить: Table_Abstract implements Rollable. Деревянный стол, например, можно сложить: Table_Wood implements Foldable.
Обрати внимание, что Rollable (с колесиками) может быть не только стол, но и стул, кровать, то есть совершенно другие типы объектов. Метод roll() будет у них всех реализован по-разному, поэтому мы не используем тут абстрактный класс типа НечтоКатящееся. Тем более что один класс может реализовывать множество интерфейсов, а абстрактный класс можно унаследовать только один. Стол должен быть одновременно с колесиками и складывающимся. Мы не можем создать абстрактный класс НечтоКатящееся, затем НечтоСкладывающееся, и создать класс Стол наследующий оба абстрактных класса. Да и не для этого они придуманы, класс всегда описывает объект, а интерфейс функционал. Абстрактный класс это обобщенное описание категории объекта, допустим стол, или стул, или кровать. От него наследуем уже какую-то конкретную разновидность, например СтолПисьменный расширяет АбстрактныйСтол реализует Складывающийся интерфейс.
А можно и оба интерфейса, пусть стол будет Складывающийся и Катящийся.
Затем создаем класс КроватьДвуспальная расширяет АбстрактнуюКровать реализует Катящийся интерфейс.

Короче абстрактный класс это обобщение, чтобы не копипастить общие методы и свойства по всем классам-наследникам, мы их группируем в одном классе.
Интерфейс это описание функционала, один класс может реализовывать множество интерфейсов. И один и тот же интерфейс может быть использован множеством классов.
Интерфейс не имеет реализации, он только декларирует, что у класса обязан быть определенный метод, а реализация может быть какая угодно, нас это не интересует, она инкапсулирована внутри.
Ответы: >>1331685
Аноним 2019/01/21 11:01:17  №1331685 3
>>1331675
Спасибо
С абстрaктным классов всё ясно.

Ну а для чего и когда используют и стоит использовать интерфейс, я так и не понял особо?
В том случае когда мы не знаем какой объект ожидать и хотим что бы это был хотя бы наследник интерфейса?
Аноним 2019/01/21 11:21:15  №1331695 4
>>1331685
Чтобы показать что класс относится к данной группе или имеет данное свойство. Ну анон привел пример выше, интерфейсом Rollable мы можем пометить классы, которые можно катать.

Ну или если попробовать придумать более серьезный пример, например в какой-нибудь соцсети можно ставить лайки фотографиям, постам и пользователям. Классы, которые описывают эти сущности (Photo, User, Post), можно пометить интерфейсом Likeable. Допустим в этом интерфейсе определены 2 метода: добавить лайк (addLikeFrom(User $user)) и убрать лайк (removeLikeFrom(User $user)). Каждый класс может реализовать эти методы по своему, лишь бы они были реализованы.

После этого, когда мы пишем функцию, и хотим сказать что на вход ей надо подать любой объект, который можно лайкнуть, мы используем интерфейс:

function setLikeTo(Likeable $object)
{
...
}

Теперь любому программисту понятно какие объекты можно подать на вход этой функции. С другой стороны, функция получает гарантию что у переданного ей объекта есть методы addLikeFrom, removeLikeFrom.

Более того, в будущем список таких объектов можно расширить, не трогая старый код. ну например если нам надо сделать чтобы комментариям можно было ставить лайк, мы делаем чтобы класс Comment реализовал интерфейс Likeable, добавляем ему нужные методы и его теперь тоже можно передавать в функцию setLikeTo, и она будет корректно с ним работать.

То есть интерфейс это что-то вроде договоренности, которая проверяется интерпретатором PHP и он гарантирует что либо договоренность выполняется, либо программа прервется с ошибкой.

Наследование - это другое. Наследование это когда мы делаем класс расширяя другой класс. Наследуются однотипные вещи: например мы можем унаследовать Танк от СредсвоПередвижения, но мы не можем унаследовать Комментарий от Фото так как у них нет ничего общего.

Интерфейсы позволяют объединять не связанные наследованием классы.

Конечно, программа будет работать и без интерфейсов, и без абстрактных классов. Она будет работать даже вообще без классов. Но качество кода будет неприемлемым. Интерфейсы и другие средства ООП позволяют разработчику задать правила использования его классов и методов, описать их. Например, если сделать функцию setLikeTo выше без исплоьзования интерфейсов, нет гарантий что на вход ей дадут правильный объект, и вообще непонятно что ей можно дать на вход. Код становится менее понятным, требует больше времени на работу с ним, легче допустить ошибку.

ООП в первую очередь делался для больших проектов, где очень много кода. Без соблюдения правил ООП код станет настолько запутанным, что любые правки будут вызывать ошибки и будет уходить много времени на их исправление. В коде на 100 или 1000 строчек конечно это не заметно. А например, код ОС андроид содержит тысячи классов (хоть они и не на PHP, а на Яве, но ООП там примерно такой же).

Обычно интерфейсы используются во всяких фреймворках и библиотеках. Ну к примеру фреймворк может содержать в себе код для проверки прав пользователей, но не содержать конкретного класса который представляет пользователя, а только интерфейс. В этом случае ты дeлаешь свой класс как тебе надо, реализуешь интерфейс и фреймворк может с твоим классом взаимодействовать.

Если ты не уверен где надо применять интерфейсы, не применяй их пока.
Ответы: >>1331725
Аноним 2019/01/21 11:50:34  №1331725 5
>>1331695
>То есть интерфейс это что-то вроде договоренности
Захотелось добавить, что часто для описания подобной "договоренности" используется слово "контракт". На самом деле повседневное совершенно дело встретиться с тонной контрактов хоть в пхп, хоть в джаве, хоть где либо еще. Просто ремарка, чтобы увидев контракты репозиториев каких-нибудь не было остолбенения.