2008-08-21 9 views
187

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

Abstract classes Позвольте вам сделать то же самое вместе с добавлением кода в метод.

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

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

+3

Вы должны прочитать это: http://stackoverflow.com/a/384067/14673 – 2014-08-15 14:20:47

+0

уверен, что это психологическая помощь и коммуникационная помощь. интерфейсы выступают в качестве отличных инструментов обучения для вашего api, поскольку они объединяют службы, которые ваш api предоставляет вместе абстрактным образом, который можно прочитать, не зная о реализации. Это дорого, но, поскольку люди, которые чувствуют себя комфортно с интерфейсом, уже могут использовать функции напрямую, не требуя классов, тем самым сохраняя указатель. без языковых интерфейсов, может быть сложно планировать заранее для многих программистов, поскольку люди, привыкшие к «oop languages», часто предпочитают разрабатывать с интерфейсами, а не на бумаге. – Dmitry 2017-09-16 19:54:45

ответ

127

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

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

+31

Можно также сказать, что * Интерфейсы обеспечивают дизайн для класса с нулевой реализацией. * Абстрактные классы предоставляют некоторый дизайн, с некоторой реализацией. Абстрактные классы наиболее полезны, когда дочерние классы имеют сходство с реализацией, но отличаются в некоторых реализациях. – Jrgns 2012-02-09 13:29:33

+0

@Craig. Не существует неотъемлемой проблемы с множественным наследованием, только текущие языки недостаточно мощны, чтобы правильно их реализовать. «Проблемы» на самом деле могут быть исправлены довольно легко, например, заявив, что явный путь наследования для унаследованных функций с тем же именем может разрешить дилемму алмаза. – Pacerier 2015-03-07 23:33:21

115

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

+0

Это заставило меня понять это немного. Это похоже на пространство имен, поэтому общий код проще в использовании и без конфликтов. Это проще, когда два человека делают занятия на одной базе, не так ли? – Soaku 2017-07-12 07:47:50

+0

Не нужно ли отличать общую концепцию «интерфейса» от конкретных интерфейсов на языке, таком как PHP? Любая функция, например, имеет «интерфейс», который определяет, как вы ее используете, и скрывает ее реализацию. Таким образом, такой «контрактный» интерфейс не требует специальной языковой функции. Поэтому языковая функция должна быть для чего-то другого (или что-то дополнительно)., – DaveInCaz 2017-10-11 19:37:56

18

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

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

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

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

+8

В PHP интерфейсы содержат только декларацию метода, а не фактическую реализацию. Однако абстрактные классы позволяют вам «добавлять код» к методам, которые должны быть унаследованы классами, которые его расширяют. Я считаю, что это различие в том, что имел в виду mk. – nocash 2009-05-24 17:29:30

5

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

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

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

5

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

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()), но не реализует интерфейс.

4

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

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

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

3

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

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

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

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

20

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

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

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

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

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

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

9

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

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

    класс автомобилей реализует EngineInterface, BodyInterface, SteeringInterface {

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

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

№ 4 это, вероятно, самый очевидный вариант использования, nnot адрес с абстрактными классами.

От мышления в Java:

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

46

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

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

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

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

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

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

// 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() будет иметь одну и ту же подпись (одинаковые типы и одинаковое количество параметров) во всех классах, реализующих интерфейс.Таким образом, вы можете быть уверены, что класс ANY, который реализует интерфейс IPersonService, будет иметь способ Create() (в этом примере) и ему потребуется только один параметр ($personObject) для вызова/использования.

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

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

9

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

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

<?php 

interface ImportableFeed 
{ 
    public function getEvents(); 
} 

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

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

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

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

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

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

1

Ниже приведены точки для PHP Interface

  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); 
0

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

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

2. Все методы в интерфейсе должны быть в Публикация видимость область.

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

        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 

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

 Смежные вопросы

  • Нет связанных вопросов^_^