Интерфейсы существуют не как база для расширения классов, а как карта необходимых функций.
Ниже приведен пример использования интерфейса, в котором абстрактный класс не подходит:
допустим, у меня есть приложение календаря, которое позволяет пользователям импортировать данные календаря из внешних источников. Я написал бы классы для обработки импорта каждого типа источника данных (ical, rss, atom, json). Каждый из этих классов реализовывал бы общий интерфейс, который гарантировал бы, что все они имеют общие публичные методы, необходимые моему приложению для получения данных.
<?php
interface ImportableFeed
{
public function getEvents();
}
Затем, когда пользователь добавляет новый фид, я могу определить тип фида и использовать класс, разработанный для этого типа, для импорта данных. Каждый класс, написанный для импорта данных для определенного фида, будет иметь совершенно другой код, в противном случае между классами может быть очень мало общего, за исключением того факта, что они необходимы для реализации интерфейса, позволяющего моему приложению использовать их. Если бы я использовал абстрактный класс, я мог бы очень легко проигнорировать тот факт, что я не переопределил метод getEvents (), который затем нарушил бы мое приложение в этом случае, тогда как использование интерфейса не позволило бы моему приложению работать, если ЛЮБОЙ из методов определенные в интерфейсе не существуют в классе, который его реализовал. Моему приложению не нужно заботиться о том, какой класс он использует для получения данных из канала,
Чтобы продвинуться дальше, интерфейс оказывается чрезвычайно полезным, когда я возвращаюсь к своему календарному приложению с намерением добавить другой тип канала. Использование интерфейса ImportableFeed означает, что я могу продолжать добавлять больше классов, которые импортируют различные типы каналов, просто добавляя новые классы, которые реализуют этот интерфейс. Это позволяет мне добавлять тонны функциональности, не прибегая к ненужным объемам в моем базовом приложении, поскольку мое базовое приложение зависит только от наличия открытых методов, необходимых для интерфейса, так как мои новые классы импорта каналов реализуют интерфейс ImportableFeed, тогда я знаю, я могу просто бросить его на место и продолжать двигаться.
Это просто очень простое начало. Затем я могу создать другой интерфейс, который могут потребоваться для реализации всех моих классов календаря, который предлагает больше функций, специфичных для типа фида, который обрабатывает класс. Другим хорошим примером может быть метод проверки типа корма и т. Д.
Это выходит за рамки вопроса, но поскольку я использовал приведенный выше пример: интерфейсы поставляются со своим собственным набором проблем, если используются таким образом. Я считаю, что мне нужно обеспечить вывод, возвращаемый из методов, реализованных для соответствия интерфейсу, и для достижения этого я использую IDE, которая читает блоки PHPDoc и добавляю тип возврата в качестве подсказки типа в блоке PHPDoc интерфейса, который затем перевести на конкретный класс, который его реализует. Мои классы, которые используют выходные данные классов, которые реализуют этот интерфейс, будут, по крайней мере, знать, что ожидают массив, возвращенный в этом примере:
<?php
interface ImportableFeed
{
/**
* @return array
*/
public function getEvents();
}
Не так много места для сравнения абстрактных классов и интерфейсов. Интерфейсы - это просто карты, которые при реализации требуют, чтобы класс имел набор открытых интерфейсов.