Інтерфейси існують не як база, на якій можуть розширюватися класи, а як карта необхідних функцій.
Далі наведено приклад використання інтерфейсу, де абстрактний клас не підходить:
Скажімо, у мене є програма календаря, яка дозволяє користувачам імпортувати дані календаря із зовнішніх джерел. Я писав би класи для обробки імпорту кожного типу джерел даних (ical, rss, atom, json). Кожен із цих класів реалізував би загальний інтерфейс, який би забезпечив, щоб усі вони мали загальнодоступні методи, необхідні моїй програмі для отримання даних.
<?php
interface ImportableFeed
{
public function getEvents();
}
Тоді, коли користувач додає новий канал, я можу визначити тип його каналу та використовувати клас, розроблений для цього типу, для імпорту даних. Кожен клас, написаний для імпорту даних для певного каналу, мав би зовсім інший код, інакше може бути дуже мало подібності між класами поза тим, що вони потрібні для реалізації інтерфейсу, який дозволяє моїй програмі споживати їх. Якби я використовував абстрактний клас, я міг би дуже легко проігнорувати той факт, що я не перекрив метод getEvents (), який би порушив мою програму в цьому випадку, тоді як використання інтерфейсу не дозволить моєму додатку запускатися, якщо БУДЬ-хто з методів визначені в інтерфейсі не існують у класі, який його реалізував. Моєму додатку не важливо, який клас він використовує для отримання даних із каналу,
Щоб зробити цей крок далі, інтерфейс виявляється надзвичайно корисним, коли я повертаюся до свого календаря з наміром додати ще один тип каналу. Використання інтерфейсу ImportableFeed означає, що я можу продовжувати додавати більше класів, які імпортують різні типи каналів, просто додаючи нові класи, що реалізують цей інтерфейс. Це дозволяє мені додати безліч функціональних можливостей без необхідності додавати основну масу в основний додаток, оскільки моє основне додаток покладається лише на те, що існують загальнодоступні методи, які потрібен інтерфейс, доки мої нові класи імпорту каналів реалізують інтерфейс ImportableFeed, то я знаю, що я можу просто скинути його на місце і продовжувати рухатись.
Це лише дуже простий початок. Потім я можу створити інший інтерфейс, для якого всі мої календарі можуть бути потрібні для впровадження, що пропонує більше функціональних можливостей, характерних для типу каналу, який обробляє клас. Ще одним хорошим прикладом може бути метод перевірки типу каналу тощо.
Це виходить за рамки питання, але оскільки я використав приклад вище: Інтерфейси поставляються із власним набором питань, якщо вони використовуються таким чином. Мені здається, що потрібно забезпечити вихід, який повертається з методів, реалізованих для відповідності інтерфейсу, і для досягнення цього я використовую IDE, який читає блоки PHPDoc і додає тип повернення як підказку типу в блок PHPDoc інтерфейсу, який буде потім перевести на конкретний клас, який його реалізує. Мої класи, які споживають дані з класів, що реалізують цей інтерфейс, принаймні знають, що очікує масив, повернутий у цьому прикладі:
<?php
interface ImportableFeed
{
/**
* @return array
*/
public function getEvents();
}
Немало місця для порівняння абстрактних класів та інтерфейсів. Інтерфейси - це просто карти, які при реалізації вимагають, щоб клас мав набір загальнодоступних інтерфейсів.