Различия как теоретические, так и практические:
Пример — интерфейс:
// define what any class implementing this must be capable of
interface IRetrieveData {
// retrieve the resource
function fetch($url);
// get the result of the retrieval (true on success, false otherwise)
function getOperationResult();
// what is this class called?
function getMyClassName();
}
Теперь у нас есть набор требований, которые будут проверяться для каждого реализующего это класса. Давайте создадим абстрактный класс и его дочерние элементы:
// define default behavior for the children of this class
abstract class AbstractRetriever implements IRetrieveData {
protected $result = false;
// define here, so we don't need to define this in every implementation
function getResult() {
return $result;
}
// note we're not implementing the other two methods,
// as this will be very different for each class.
}
class CurlRetriever extends AbstractRetriever {
function fetch($url) {
// (setup, config etc...)
$out = curl_execute();
$this->result = !(curl_error());
return $out;
}
function getMyClassName() {
return 'CurlRetriever is my name!';
}
}
class PhpRetriever extends AbstractRetriever {
function fetch($url) {
$out = file_get_contents($url);
$this->result = ($out !== FALSE);
return $out;
}
function getMyClassName() {
return 'PhpRetriever';
}
}
Совершенно другой абстрактный класс (не связанный с интерфейсом) с подклассом, который реализует наш интерфейс:
abstract class AbstractDog {
function bark() {
return 'Woof!';
}
}
class GoldenRetriever extends AbstractDog implements IRetrieveData {
// this class has a completely different implementation
// than AbstractRetriever
// so it doesn't make sense to extend AbstractRetriever
// however, we need to implement all the methods of the interface
private $hasFetched = false;
function getResult() {
return $this->hasFetched;
}
function fetch($url) {
// (some retrieval code etc...)
$this->hasFetched = true;
return $response;
}
function getMyClassName() {
return parent::bark();
}
}
Теперь, в другом коде, мы можем сделать это:
function getStuff(IRetrieveData $retriever, $url) {
$stuff = $retriever->fetch($url);
}
и нам не нужно беспокоиться о том, какой из ретриверов (cURL, PHP или Golden) будет передан и как они собираются достичь цели, поскольку все они должны вести себя одинаково. Вы могли бы сделать это и с абстрактным классом, но тогда вы ограничиваете себя на основе предка классов, а не его возможностей.
Множественное и одиночное наследование:
Реализация:
Это то, что я знаю наизусть.
Вот хорошее описание различия между ними:
http://www.supertom.com/code/php_abstracts_and_interfaces.html
Все сводится к тому факту, что extends является отношением «is-a», в то время как -отношения.
"An Abstract Class can contain default Implementation, where as an
Interface should not contain any implementation at all. "
Что касается того, что использовать в реальных приложениях... все зависит от контекста.
Например, на днях здесь был вопрос о реализации игры с использованием PHP. Здесь у них был абстрактный класс, определяющий монстра, и любой монстр мог быть основан на этом абстрактном классе. Это позволяло наследовать свойства монстров по умолчанию.
Принимая во внимание, что для интерфейса вы определяете общие требования к способу «взаимодействия» (извините за использование термина в объяснении) некоторой системы. Пример этого из недавнего проекта, который я сделал. Я реализовал мыльный клиент на php для взаимодействия с мыльным сервером от третьей стороны. Этот интерфейс определяет, какие методы мыла поддерживает сервер, и поэтому любой класс, реализующий мой интерфейс, должен определять эти методы.
Метафора, которую я слышал лучше всего, заключалась в том, что абстрактный класс — это полузавершенный класс. Это не сделано; ты еще должен закончить его. Поэтому, когда вы создаете класс, расширяющий абстрактный класс, вы просто завершаете то, что начали в абстрактном классе. По этой же причине вы не можете создать экземпляр абстрактного класса; то, что вы сделали его абстрактным, указывает на его неполноту. Он все еще нуждается в некоторых дополнительных функциях.
Интерфейс просто гарантирует, что в реализующем его классе должны существовать определенные методы, каждый с определенным количеством аргументов. Так что впоследствии программист, использующий класс, реализующий конкретный интерфейс, может быть уверен, что сможет вызывать определенные методы этого класса.
См. эту страницу: 5 Основное различие между абстрактным классом и интерфейсом в PHP
И это: связанный ответ StackOverflow .