Сведения о вопросе

Mathprofi

23:27, 29th August, 2020

Теги

php   oop   interface   theory    

В чем смысл интерфейсов в PHP?

Просмотров: 203   Ответов: 15

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

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

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

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



  Сведения об ответе

SKY

22:40, 1st August, 2020

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

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


  Сведения об ответе

ITSME

18:32, 17th August, 2020

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


  Сведения об ответе

ITSME

11:47, 29th August, 2020

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

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

"diamond problem" (иногда упоминается как " смертельный алмаз из смерть") - это двусмысленность, возникающая при наследовании двух классов B и C С и класс D наследует от обоих B и C. Если есть метод в случае, если B и C были переопределены, А D не переопределяет их, то какой вариант метода Д'наследования: что б, или C?

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

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

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

// 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() может отличаться для разных классов, не влияя на код "outside", который вызывает этот метод. Весь внешний код должен знать, что метод Create() имеет 1 параметр ($personObject), потому что именно так внешний код будет использовать/вызывать метод. Внешний код не заботится о том, что происходит внутри метода; он только должен знать, как его использовать/вызывать.

Вы можете сделать это и без интерфейса, но если вы используете интерфейс, то это "safer" (потому что он предотвращает ошибки). Интерфейс гарантирует, что метод Create() будет иметь одинаковую сигнатуру (одинаковые типы и одинаковое количество параметров) во всех классах, реализующих интерфейс. Таким образом, вы можете быть уверены, что класс ANY, реализующий интерфейс IPersonService , будет иметь метод Create() (в данном примере) и потребуется только 1 параметр ($personObject ), чтобы получить called/used.

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

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


  Сведения об ответе

DO__IT

21:44, 25th August, 2020

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

В то время как наследование от абстрактного класса является отношением "is a", это не всегда то, что вы хотите, и реализация интерфейса является скорее отношением "acts like a". Это различие может быть весьма существенным в определенных контекстах.

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

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

Таким образом, я говорю, что подкласс FooUser-это NOT учетная запись, но DOES действует как редактируемый объект. Аналогично BarAccount расширяется от учетной записи, но не является подклассом пользователя, но реализует редактируемый, список и также версионный.

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


  Сведения об ответе

qwerty101

16:42, 17th August, 2020

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

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

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

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


  Сведения об ответе

SSESION

08:31, 20th August, 2020

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

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

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


  Сведения об ответе

VERSUION

13:52, 13th August, 2020

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

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

<?php

interface ImportableFeed 
{
    public function getEvents();
}

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

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

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

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

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

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


  Сведения об ответе

ЯЯ__4

13:34, 17th August, 2020

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

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

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

Динамически типизированные языки имеют понятие "duck-typing", где вам не нужны интерфейсы; вы можете свободно предположить, что объект имеет метод, который вы вызываете. Это работает вокруг проблемы в статически типизированных языках, где ваш объект имеет некоторый метод (в моем примере, read()), но не реализует интерфейс.


  Сведения об ответе

dumai

18:53, 7th August, 2020

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

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

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


  Сведения об ответе

lool

09:11, 13th August, 2020

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

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

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


  Сведения об ответе

lool

05:15, 3rd August, 2020

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

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

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

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


  Сведения об ответе

JUST___

01:35, 21st August, 2020

Интерфейсы подобны вашим генам.

Абстрактные классы похожи на ваших настоящих родителей.

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


  Сведения об ответе

ЯЯ__4

14:13, 7th August, 2020

Ниже приведены точки для интерфейса 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);


  Сведения об ответе

qwerty101

10:52, 26th August, 2020

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

1.Interfaces может включать абстрактные методы и константы, но не может содержать конкретные методы и переменные.

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

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

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


  Сведения об ответе

DO__IT

21:19, 24th August, 2020

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

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

правило

  1. Интерфейс не может быть инстанцирован.

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

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

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

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

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

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

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

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


Ответить на вопрос

Чтобы ответить на вопрос вам нужно войти в систему или зарегистрироваться