Какой смысл интерфейсов в PHP?

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

Абстрактные классы позволяют вам делать то же самое, наряду с добавлением кода в метод.

Теперь, если вы можете достичь той же цели с помощью абстрактных классов, зачем нам вообще нужна концепция интерфейсов?

Мне сказали, что это связано с теорией ОО от C ++ до Java, на которой основаны ООП в PHP. Является ли эта концепция полезной в Java, но не в PHP? Это просто способ избежать засорения заполнителей в абстрактном классе? Я что-то упускаю?

21.08.2008 16:35:20
Вы должны прочитать это: stackoverflow.com/a/384067/14673
Luc M 15.08.2014 14:20:47
Я уверен, что это умственная помощь и помощь в общении. интерфейсы выступают в качестве отличных инструментов обучения для вашего API, так как они объединяют сервисы, которые ваш API представляет вместе, абстрактным способом, который можно прочитать, не зная о реализации. Это дорого, но поскольку люди, которые знакомы с интерфейсом, уже могут использовать функции напрямую, не нуждаясь в классах, сохраняя указатель. без определенных языком интерфейсов для многих программистов может быть сложно планировать заранее, так как люди, привыкшие к «неопознанным языкам», часто предпочитают проектировать с интерфейсами, а не на бумаге.
Dmitry 16.09.2017 19:54:45
15 ОТВЕТОВ
РЕШЕНИЕ

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

Интерфейсы - это компромисс. Большинство проблем с множественным наследованием неприменимы к абстрактным базовым классам, поэтому большинство современных языков в настоящее время отключают множественное наследование, но при этом вызывают интерфейсы абстрактных базовых классов и позволяют классу «реализовывать» столько желаемых классов.

141
3.03.2015 01:35:35
Можно также сказать, что * Интерфейсы предоставляют дизайн для класса с нулевой реализацией. * Абстрактные классы обеспечивают некоторый дизайн, с некоторой реализацией. Абстрактные классы наиболее полезны, когда дочерние классы имеют некоторые общие черты реализации, но отличаются в определенных реализациях.
Jrgns 9.02.2012 13:29:33
@Craig, с множественным наследованием нет врожденной проблемы, просто текущие языки недостаточно мощны, чтобы правильно их реализовать. «Проблемы» на самом деле могут быть решены довольно легко, например, указание явного пути наследования для наследуемых функций с тем же именем может разрешить дилемму алмаза.
Pacerier 7.03.2015 23:33:21
Это не то, что интерфейсы вообще. Это не компромисс по множественному наследованию, а создание концептуального и абстрактного контракта для объектов, которые нужно реализовать, и для использования другими объектами / методами. Интерфейсы являются инструментом для полиморфизма, а не для прямого наследования.
Madara's Ghost 13.05.2015 14:47:47

Эта концепция полезна в объектно-ориентированном программировании. Для меня я думаю об интерфейсе как о контракте. До тех пор, пока мой класс и ваш класс договариваются о подписании этого метода, мы можем «взаимодействовать». Что касается абстрактных классов, то я считаю их более базовыми классами, которые ограничивают некоторые методы, и мне нужно заполнить детали.

122
21.08.2008 16:39:23
Это заставило меня немного понять это. Это как с пространствами имен - так что общий код проще в использовании и без конфликтов. Проще, когда два человека проводят занятия на одной базе, верно?
RedClover 12.07.2017 07:47:50
Разве нам не нужно отличать общую концепцию «интерфейса» от конкретных интерфейсов в языке, подобном PHP? Любая функция, например, имеет «интерфейс», который определяет, как вы ее используете, и скрывает ее реализацию. Так что такой «договорный» интерфейс не требует специальной языковой функции. Поэтому языковая особенность должна быть для чего-то другого (или чего-то дополнительного).,
UuDdLrLrSs 11.10.2017 19:37:56

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

Я не уверен, что вы имеете в виду, не имея возможности добавлять код в методы - потому что вы можете. Применяете ли вы интерфейс к абстрактному классу или к классу, который его расширяет?

Метод в интерфейсе, применяемый к абстрактному классу, должен быть реализован в этом абстрактном классе. Однако примените этот интерфейс к расширяющему классу, и метод требует реализации только в расширяющем классе. Я могу ошибаться - я не использую интерфейсы так часто, как мог бы / должен.

Я всегда думал об интерфейсах как о шаблоне для внешних разработчиков или о дополнительном наборе правил, чтобы убедиться, что все правильно.

21
21.08.2008 16:44:38
В PHP интерфейсы содержат только объявление метода, а не фактическую реализацию. Абстрактные классы, однако, позволяют вам «добавлять код» в методы, наследуемые классами, которые его расширяют. Я полагаю, что это различие - то, что имел в виду mk.
nocash 24.05.2009 17:29:30

На мой взгляд, интерфейсы должны быть предпочтительнее, чем нефункциональные абстрактные классы. Я не был бы удивлен, если бы там был даже удар производительности, поскольку есть только один экземпляр объекта вместо того, чтобы анализировать два, комбинируя их (хотя, я не могу быть уверен, я не знаком с внутренней работой) ООП PHP).

Это правда, что интерфейсы менее полезны / значимы, чем, скажем, Java. С другой стороны, PHP6 введет еще больше хинтинга типов, включая хинтинг типов для возвращаемых значений. Это должно добавить некоторую ценность интерфейсам PHP.

tl; dr: interfaces определяет список методов, которым необходимо следовать (например, API), в то время как абстрактный класс предоставляет некоторые базовые / общие функциональные возможности, которые подклассы уточняют для конкретных потребностей.

6
21.08.2008 16:47:11
PHP 6 никогда не выйдет. PHP 6 был проектом, который разрабатывался с 2005 по 2010 годы, но был отложен и в конечном итоге отменен. PHP 7 является следующей версией, в основном, чтобы избежать путаницы с прежним проектом PHP 6.
Ashu Jha 19.09.2016 11:06:03

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

interface Readable {
  String read();
}

List<Readable> readables; // dunno what these actually are, but we know they have read();
for(Readable reader : readables)
  System.out.println(reader.read());

Во многих случаях не имеет смысла предоставлять базовый класс, абстрактный или нет, потому что реализации сильно различаются и не имеют ничего общего, кроме нескольких методов.

Языки с динамической типизацией имеют понятие «типизированная утка», когда вам не нужны интерфейсы; Вы можете предположить, что у объекта есть метод, который вы вызываете. Это решает проблему в статически типизированных языках, где у вашего объекта есть некоторый метод (в моем примере read ()), но не реализует интерфейс.

8
21.08.2008 16:52:24

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

В PHP вы можете применять несколько интерфейсов, разделяя их запятой (я думаю, я не считаю это чистым решением).

Что касается нескольких абстрактных классов, у вас может быть несколько абстрактов, расширяющих друг друга (опять же, я не совсем уверен в этом, но я думаю, что видел это где-то раньше). Единственное, что вы не можете продлить, это последний класс.

5
21.08.2008 16:53:24

Интерфейсы не дадут вашему коду никакого повышения производительности или чего-то в этом роде, но они могут значительно улучшить его поддержку. Это правда, что абстрактный класс (или даже неабстрактный класс) можно использовать для установления интерфейса с вашим кодом, но правильные интерфейсы (те, которые вы определяете с помощью ключевого слова и которые содержат только сигнатуры методов) просто проще перебрать и прочитать.

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

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

Однако тот факт, что ваш вопрос касается PHP, делает вещи немного более интересными. Печатание на интерфейсах все еще не является чрезвычайно необходимым в PHP, где вы можете в значительной степени передать любой метод, независимо от его типа. Вы можете статически набирать параметры метода, но некоторые из них не работают (я думаю, что String вызывает некоторые сбои). Соедините это с тем фактом, что вы не можете печатать большинство других ссылок, и нет особой ценности в попытках принудительной статической типизации в PHP ( на данный момент ). И из-за этого, значение интерфейсов в PHP , на данный моментгораздо меньше, чем в более строго типизированных языках. Они имеют преимущество читабельности, но мало что еще. Множественная реализация даже не выгодна, потому что вам все равно нужно объявлять методы и предоставлять им тела в реализаторе.

4
21.08.2008 17:06:42

Разница между использованием интерфейса и абстрактного класса больше для меня связана с организацией кода, чем с применением самого языка. Я часто использую их при подготовке кода для работы с другими разработчиками, чтобы они не выходили за рамки предполагаемых шаблонов проектирования. Интерфейсы - это своего рода «проектирование по контракту», при котором ваш код соглашается отвечать на предписанный набор вызовов API, которые могут исходить из кода, к которому у вас нет доступа.

Хотя наследование от абстрактного класса является отношением «является», это не всегда то, что вам нужно, а реализация интерфейса - это скорее отношение «действует как». Эта разница может быть довольно значительной в определенных контекстах.

Например, допустим, у вас есть абстрактный класс Account, из которого расширяются многие другие классы (типы учетных записей и т. Д.). У него есть определенный набор методов, которые применимы только к этой группе типов. Однако некоторые из этих подклассов учетных записей реализуют Versionable, Listable или Editable, чтобы их можно было бросать в контроллеры, которые ожидают использования этих API. Контроллеру все равно, какой это тип объекта

В отличие от этого, я также могу создать объект, который не выходит за пределы Account, скажем, абстрактный класс User, и при этом реализовать Listable и Editable, но не Versionable, что здесь не имеет смысла.

Таким образом, я говорю, что подкласс FooUser НЕ является учетной записью, но действует как редактируемый объект. Аналогично, BarAccount расширяется от Account, но не является подклассом User, но реализует Editable, Listable и также Versionable.

Добавление всех этих API-интерфейсов для Editable, Listable и Versionable в сами абстрактные классы не только будет беспорядочным и уродливым, но либо приведет к дублированию общих интерфейсов в Account и User, либо вынудит мой объект User реализовать Versionable, возможно, просто для исключение.

24
27.08.2008 16:36:48
Это прямо здесь. Жестко предписывайте разработчикам использовать ваши методы, не расширяя и не перезаписывая их
Nick 30.11.2017 21:44:45

Вы будете использовать интерфейсы в PHP:

  1. Чтобы скрыть реализацию - установите протокол доступа к классу объектов, измените базовую реализацию без рефакторинга во всех местах, где вы использовали эти объекты
  2. Для проверки типа - например, чтобы убедиться, что параметр имеет определенный тип $object instanceof MyInterface
  3. Для принудительной проверки параметров во время выполнения
  4. Для реализации нескольких поведений в одном классе (создание сложных типов)

    Класс Car реализует EngineInterface, BodyInterface, SteeringInterface {

так что Carобъект может теперь start(), stop()(EngineInterface) или goRight(), goLeft()(интерфейс управления)

и другие вещи, о которых я не могу думать прямо сейчас

Номер 4, пожалуй, самый очевидный вариант использования, к которому нельзя обращаться с абстрактными классами.

Из мышления на Java:

Интерфейс говорит: «Вот как будут выглядеть все классы, которые реализуют этот конкретный интерфейс». Таким образом, любой код, который использует определенный интерфейс, знает, какие методы могут быть вызваны для этого интерфейса, и это все. Таким образом, интерфейс используется для установления «протокола» между классами.

12
20.01.2014 09:37:12

Зачем вам интерфейс, если уже есть абстрактные классы? Для предотвращения множественного наследования (может вызвать несколько известных проблем).

Одна из таких проблем:

«Алмазная проблема» (иногда называемая «смертельным алмазом смерти») - это неоднозначность, которая возникает, когда два класса B и C наследуют от A, а класс D наследует от B и C. Если в A есть метод, который B и C переопределили, и D не переопределяет его, тогда какая версия метода наследуется D: версия B или версия C?

Источник: https://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem

Почему / Когда использовать интерфейс? Пример ... Все машины в мире имеют одинаковый интерфейс (методы) ... AccelerationPedalIsOnTheRight(), BrakePedalISOnTheLeft(). Представьте, что у каждой автомобильной марки эти "методы" будут отличаться от другой марки. У БМВ были бы тормоза на правой стороне, и у Хонды были бы тормоза на левой стороне колеса. Люди должны были бы узнать, как работают эти «методы» каждый раз, когда покупали автомобиль другой марки. Вот почему хорошая идея иметь один и тот же интерфейс в нескольких «местах».

Что интерфейс делает для вас (почему кто-то даже использовал бы его)? Интерфейс предотвращает от вас «ошибки» (он гарантирует, что все классы, которые реализуют определенный интерфейс, будут иметь методы, которые находятся в интерфейсе).

// Methods inside this interface must be implemented in all classes which implement this interface.
interface IPersonService
{   
    public function Create($personObject);
}

class MySqlPerson implements IPersonService
{
    public function Create($personObject)
    {
        // Create a new person in MySql database.
    }
}

class MongoPerson implements IPersonService
{
    public function Create($personObject)
    {
        // Mongo database creates a new person differently then MySQL does. But the code outside of this method doesn't care how a person will be added to the database, all it has to know is that the method Create() has 1 parameter (the person object).
    }
}

Таким образом, Create()метод всегда будет использоваться одинаково. Неважно, если мы используем MySqlPersonкласс или MongoPersonкласс. То, как мы используем метод, остается прежним (интерфейс остается прежним).

Например, он будет использоваться следующим образом (везде в нашем коде):

new MySqlPerson()->Create($personObject);
new MongoPerson()->Create($personObject);

Таким образом, что-то подобное не может произойти:

new MySqlPerson()->Create($personObject)
new MongoPerson()->Create($personsName, $personsAge);

Намного проще запомнить один интерфейс и использовать его везде, чем несколько разных.

Таким образом, внутренняя часть Create()метода может быть разной для разных классов, не влияя на «внешний» код, который вызывает этот метод. Внешний код должен знать только то, что метод Create()имеет 1 параметр ( $personObject), потому что именно так внешний код будет использовать / вызывать метод. Внешний код не заботится о том, что происходит внутри метода; это только должно знать, как использовать / назвать это.

Вы можете сделать это и без интерфейса, но если вы используете интерфейс, он «безопаснее» (потому что он предотвращает ошибки). Интерфейс гарантирует, что метод Create()будет иметь одинаковую сигнатуру (одинаковые типы и одинаковое количество параметров) во всех классах, которые реализуют интерфейс. Таким образом, вы можете быть уверены, что ЛЮБОЙ класс, который реализует IPersonServiceинтерфейс, будет иметь метод Create()(в этом примере) и будет нуждаться только в 1 параметре ( $personObject) для вызова / использования.

Класс, который реализует интерфейс, должен реализовать все методы, которые интерфейс делает / имеет.

Я надеюсь, что я не повторял себя слишком много.

68
13.12.2017 02:05:07
Действительно хорошая аналогия с автомобильными педалями!
James 1.06.2019 00:30:29

Интерфейсы существуют не как база, на которую могут расширяться классы, а как карта требуемых функций.

Ниже приведен пример использования интерфейса, в котором абстрактный класс не подходит:
допустим, у меня есть приложение календаря, которое позволяет пользователям импортировать данные календаря из внешних источников. Я написал бы классы для обработки импорта каждого типа источника данных (ical, rss, atom, json). Каждый из этих классов реализовывал бы общий интерфейс, который гарантировал бы, что все они имеют общие публичные методы, необходимые моему приложению для получения данных.

<?php

interface ImportableFeed 
{
    public function getEvents();
}

Затем, когда пользователь добавляет новый канал, я могу определить его тип и использовать класс, разработанный для этого типа, для импорта данных. Каждый класс, написанный для импорта данных для определенного фида, будет иметь совершенно другой код, в противном случае между классами может быть очень мало общего, за исключением того факта, что они необходимы для реализации интерфейса, позволяющего моему приложению использовать их. Если бы я использовал абстрактный класс, я мог бы очень легко проигнорировать тот факт, что я не переопределил метод getEvents (), который затем нарушил бы мое приложение в этом случае, тогда как использование интерфейса не позволило бы моему приложению работать, если ЛЮБОЙ из методов определенные в интерфейсе не существуют в классе, который его реализовал. Моему приложению не нужно заботиться о том, какой класс он использует для получения данных из канала,

Чтобы продвинуться дальше, интерфейс оказывается чрезвычайно полезным, когда я возвращаюсь к своему календарному приложению с намерением добавить другой тип канала. Использование интерфейса ImportableFeed означает, что я могу продолжать добавлять больше классов, которые импортируют различные типы каналов, просто добавляя новые классы, которые реализуют этот интерфейс. Это позволяет мне добавлять тонны функциональности, не прибегая к ненужной массовой загрузке моего основного приложения, поскольку мое основное приложение зависит только от наличия общедоступных методов, доступных для интерфейса, так что, пока мои новые классы импорта каналов реализуют интерфейс ImportableFeed, тогда я знаю, я могу просто бросить его на место и продолжать двигаться.

Это просто очень простое начало. Затем я могу создать другой интерфейс, который могут потребоваться для реализации всех моих классов календаря, который предлагает больше функций, специфичных для типа фида, который обрабатывает класс. Другим хорошим примером может служить метод проверки типа корма и т. Д.

Это выходит за рамки вопроса, но поскольку я использовал приведенный выше пример: интерфейсы поставляются со своим собственным набором проблем, если используются таким образом. Мне нужно убедиться, что выходные данные возвращаются из методов, реализованных для соответствия интерфейсу, и для достижения этого я использую IDE, которая читает блоки PHPDoc и добавляет тип возвращаемого значения в качестве подсказки типа в блоке PHPDoc интерфейса, который затем перевести на конкретный класс, который его реализует. Мои классы, которые используют выходные данные классов, которые реализуют этот интерфейс, будут, по крайней мере, знать, что ожидают массив, возвращенный в этом примере:

<?php
interface ImportableFeed 
{
    /**
     * @return array
     */
    public function getEvents();
}

Не так много места для сравнения абстрактных классов и интерфейсов. Интерфейсы - это просто карты, которые при реализации требуют, чтобы класс имел набор открытых интерфейсов.

10
30.07.2015 19:23:51
Хорошее объяснение :) Спасибо!
Razvan.432 15.09.2015 11:28:20
Просто для добавления информации: В абстрактном классе, если вы объявляете метод как абстрактный, он ведет себя как интерфейс, поэтому вы не можете игнорировать тот факт, что вы не переопределяете getEvents (). Приложение не будет работать так же, как с интерфейсом.
Rikudou_Sennin 20.04.2017 10:58:07

Ниже приведены пункты для интерфейса PHP

  1. Он используется для определения обязательных методов в классе [если вы хотите загрузить html, тогда требуется идентификатор и имя, поэтому в этом случае интерфейс включает setID и setName].
  2. Интерфейс строго заставляет класс включать все методы, определенные в нем.
  3. Вы можете определить метод только в интерфейсе с общедоступной доступностью.
  4. Вы также можете расширить интерфейс, как класс. Вы можете расширить интерфейс в php используя ключевое слово extends.
  5. Расширить несколько интерфейсов.
  6. Вы не можете реализовать 2 интерфейса, если оба используют одну и ту же функцию. Это выдаст ошибку.

Пример кода:

interface test{
    public function A($i);
    public function B($j = 20);
}

class xyz implements test{
    public function A($a){
        echo "CLASS A Value is ".$a;
    }
    public function B($b){
        echo "CLASS B Value is ".$b;
    }
}
$x = new xyz();
echo $x->A(11);
echo "<br/>";
echo $x->B(10);
2
12.01.2017 06:39:51

Мы видели, что абстрактные классы и интерфейсы похожи в том, что они предоставляют абстрактные методы, которые должны быть реализованы в дочерних классах. Тем не менее, они по-прежнему имеют следующие различия:

1. Интерфейсы могут включать абстрактные методы и константы, но не могут содержать конкретные методы и переменные.

2.Все методы в интерфейсе должны находиться в общедоступной области видимости.

3. Класс может реализовывать более одного интерфейса, в то время как он может наследовать только от одного абстрактного класса.

                                  interface                      abstract class
the code                     - abstract methods               - abstract methods
                             - constants                      - constants                  
                                                              - concrete methods
                                                              - concrete variables

access modifiers             
                             - public                         - public
                                                              - protected
                                                              - private
                                                                etc.
number of parents          The same class can implement
                           more than 1 interface              The child class can 
                                                              inherit only from 1 abstract class

Надеюсь, что это поможет любому понять!

2
16.02.2018 11:17:08

Интерфейсы как твои гены.

Абстрактные классы как твои настоящие родители.

Их цели наследственные, но в случае абстрактных классов и интерфейсов то, что наследуется, более конкретно.

2
27.09.2018 14:11:55

Я не знаю о других языках, какова концепция интерфейса там. Но для PHP, я постараюсь объяснить это. Просто наберитесь терпения и, пожалуйста, прокомментируйте, если это помогло.

Интерфейс работает как «контракты», определяя, что делает набор подклассов, но не как они это делают.

Правило

  1. Интерфейс не может быть создан.

  2. Вы не можете реализовать какой-либо метод в интерфейсе, т.е. он содержит только сигнатуру метода, но не детали (тело).

  3. Интерфейсы могут содержать методы и / или константы, но без атрибутов. Интерфейсные константы имеют те же ограничения, что и константы класса. Методы интерфейса неявно абстрактны.

  4. Интерфейсы не должны объявлять конструкторы или деструкторы, так как это детали реализации на уровне класса.
  5. Все методы в интерфейсе должны иметь публичную видимость.

Теперь давайте возьмем пример. Предположим, у нас есть две игрушки: одна - собака, а другая - кошка.

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

Когда пользователь нажимает кнопку «говорить», игрушка должна говорить, не важно, собака это или кошка.

Это хороший случай, чтобы использовать интерфейс, а не абстрактный класс, потому что реализации различны. Почему? Помните

Если вам нужно поддерживать дочерние классы, добавляя неабстрактный метод, вы должны использовать абстрактные классы. В противном случае, интерфейсы будут вашим выбором.

2
5.04.2019 05:45:30