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

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

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

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

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

Вы должны прочитать это: stackoverflow.com/a/384067/14673

Luc M 15.08.2014 18:20

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

Dmitry 16.09.2017 22:54
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
236
2
97 176
15
Перейти к ответу Данный вопрос помечен как решенный

Ответы 15

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

Это заставило меня немного это понять. Это похоже на пространства имен - общий код проще в использовании и не вызывает конфликтов. Легче, когда два человека проводят занятия на одной базе, правда?

user5147563 12.07.2017 10:47

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

StayOnTarget 11.10.2017 22:37

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

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

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

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

В PHP интерфейсы содержат только объявление метода, а не фактическую реализацию. Однако абстрактные классы позволяют «добавлять код» к методам, которые наследуются классами, которые его расширяют. Я считаю, что именно эта разница имела в виду мк.

nocash 24.05.2009 21:29
Ответ принят как подходящий

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

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

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

Jrgns 09.02.2012 17:29

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

Pacerier 08.03.2015 02:33

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

Madara's Ghost 13.05.2015 17:47

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

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

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

PHP 6 никогда не будет выпущен. PHP 6 был проектом, который разрабатывался с 2005 по 2010 год, но был отложен и в конечном итоге был отменен. PHP 7 - это следующая версия, в основном, чтобы не путать с предыдущим проектом PHP 6.

Ashu Jha 19.09.2016 14:06

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

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

I can't remember if PHP is different in this respect, but in Java, you can implement multiple Interfaces, but you can't inherit multiple abstract classes. I'd assume PHP works the same way.

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

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

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

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

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

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

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

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

Nick 01.12.2017 00:44

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

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

    class Car implements EngineInterface, BodyInterface, SteeringInterface {

so that a Car object ca now start(), stop() (EngineInterface) or goRight(),goLeft() (Steering interface)

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

Номер 4 - это, вероятно, наиболее очевидный вариант использования, который нельзя решить с помощью абстрактных классов.

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

An interface says, “This is what all classes that implement this particular interface will look like.” Thus, any code that uses a particular interface knows what methods can be called for that interface, and that’s all. So the interface is used to establish a “protocol” between classes.

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

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

The "diamond problem" (sometimes referred to as the "deadly diamond of death") is an ambiguity that arises when two classes B and C inherit from A and class D inherits from both B and C. If there is a method in A that B and C have overridden, and D does not override it, then which version of the method does D inherit: that of B, or that of 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() будет иметь одинаковую сигнатуру (одинаковые типы и одинаковое количество параметров) во всех классах, реализующих интерфейс. Таким образом, вы можете быть уверены, что ЛЮБОЙ класс, реализующий интерфейс IPersonService, будет иметь метод Create() (в этом примере), и для его вызова / использования потребуется только 1 параметр ($personObject).

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

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

Действительно красивая аналогия с автомобильными педалями!

James 01.06.2019 03:30

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

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

<?php

interface ImportableFeed 
{
    public function getEvents();
}

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

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

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

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

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

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

Хорошее объяснение :) Спасибо!

Razvan.432 15.09.2015 14:28

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

Rikudou_Sennin 20.04.2017 13:58

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

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

1.Interfaces can include abstract methods and constants, but cannot contain concrete methods and variables.

2.All the methods in the interface must be in the public visibility scope.

3.A class can implement more than one interface, while it can inherit from only one abstract class.

                                  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

Надеюсь, это поможет кому-нибудь понять!

Интерфейсы похожи на ваши гены.

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

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

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

An interface works as a "contracts", specifying what a set of subclasses does, but not how they do it.

Правило

  1. An Interface can't be instantiate.

  2. You can't implement any method in an interface,i.e. it only contains .signature of the method but not details(body).

  3. Interfaces can contain methods and/or constants, but no attributes. Interface constants have the same restrictions as class constants. Interface methods are implicitly abstract.

  4. Interfaces must not declare constructors or destructors, since these are implementation details on the class level.

  5. All the methods in an interface must have public visibility.

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

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

When the user presses speak button, the toy have to speak it doesn't matter if it's Dog or a Cat.

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

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

Другие вопросы по теме