Когда в PHP использовать интерфейсы, а когда абстрактные классы?
==================================================================

 Хочется просто разобраться, что и когда лучше использовать.  
  
  

Только не надо писать сообщения типа: «Интерфейс — это интерфейс… А абстрактный класс — это абстрактный класс Все просто». Так пишут везде, не давая конкретного ответа.  
  
  

Желательно на конкретном примере, когда лучше использовать одно, а когда другое. 

**С точки зрения архитектуры:**   

  

Интерфейс описывает свойства. Обратите внимание на классические названия интерфейсов: Throwable, Countable, Comparable, Iterable и т.д. Возьмем, к примеру, интерфейс Rollable (катящийся), и Foldable (складывающийся).  

  

Абстрактный класс же описывает сущность. Например, стол: Table\_Abstract. Стол может быть деревянным, тогда будет Table\_Wood extends Table\_Abstract. Также стол может быть хирургическим: Table\_Surgical extends Table\_Abstract. В таком случае Table\_Abstract объединяет общий свойства всех столов (скажем, площадь поверхности, наличие ножек и т.п.). А конкретный класс описывает сущность определенного типа столов.  

  

Связью же интерфейсов и классов Вы описываете свойства. Например, стол можно катить: Table\_Abstract implements Rollable. Деревянный стол, например, можно сложить: Table\_Wood implements Foldable. 

 Как пишут умные люди (Шилдт, Троелсен) в своих умных книжках, интерфейс определяет функциональные возможности, поведение — «что именно следует делать, но не как это делать» (Г.Шилдт, Полное руководство C#). В абстрактном классе «определяется лишь самая общая форма для всех его производных классов, а наполнение ее деталями предоставляется каждому из этих классов» (там же).   

  

Простой пример, в контексте графического редактора можно определить:  

Абстрактный класс — Figure (геометрическая фигура), от него могут быть образованы классы конкретных фигур — например, Rectangle, Circle и т.д.  

Интерфейс — Drawable (то, что можно нарисовать). Он может быть реализован как во всех классах конкретных фигур (Circle, Rectangle), так и в других классах, не образованных от абстрактного Figure. 

 Я бы сказал так:  

Интерфейс — это возможность задать жёсткую семантику.  

Абстрактный класс — это возможность вынести дублирующийся код и явно это отметить в иерархии. 

 К примеру, нужно написать класс для работы с кэшем.  

  

У нас есть класс Cache, который будет делать всю грязную работу. Он в свою очередь будет использовать библиотеку под определенный тип кэша (memcached, eaccelerator, ...). Для согласованности, библиотека должна реализовать интерфейс cacheInterface, чтобы класс Cache мог нормально работать. Вот небольшой пример.  

  

Интерфейс для библиотеки: 

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

Кроме того, если нужно предоставить несколько интерфейсов, а множественного наследования нет (как в PHP), то интерфейсы — единственный выход. 

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

  

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

нельзя инициализировать объект абстрактного класса — это отличие от использования обычного класса для наследования.  

  

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

 Интерфейс не представляет из себя некую самостоятельную сущность. Как пульт от телевизора, например.