The differences are both theoretical and practical:
- interface is a description of some capability your class has and advertises (so various classes implementing the same interface can be used the same way)
- abstract class can be a default implementation, containing the parts which are likely to appear in all the implementations. It doesn't have to implement the complete interface
Example - an interface:
// 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();
}
Now we have the set of requirements that will be checked for every class implementing this. Let's make an abstract class and its children:
// 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';
}
}
A completely different abstract class (unrelated to the interface), with a subclass which implements our interface:
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();
}
}
Now, in other code, we can do this:
function getStuff(IRetrieveData $retriever, $url) {
$stuff = $retriever->fetch($url);
}
and we don't have to worry which of the retrievers (cURL, PHP, or Golden) will be passed in, and how are they going to accomplish the goal, as all should be capable of behaving similarly. You could do this with an abstract class, too, but then you're restricting yourself based on the classes' ancestor, instead of its capability.