PHP中抽象类和接口的区别是什么?

8
可能重复:
PHP:接口和抽象类有什么区别? 据我所知,实现或扩展抽象或接口类的类必须使用默认方法。 我知道我们可以使用实现关键字来使用多个接口,但是我们只能扩展1个抽象类。 在实际项目中应该使用哪一个以及它们之间的区别是什么?

3
抽象类和接口有什么不同? - shamittomar
问题可能可以泛化一下... :) - ultrajohn
6个回答

12

这些差异既有理论上的,也有实践上的:

  • interface 是描述类具有和广告的某些 能力(因此,实现相同接口的各种类可以以相同的方式使用)。
  • abstract class 可以是一个默认实现,包含可能出现在所有实现中的部分。它不必实现完整的接口。

例如- 一个接口:

// 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)将被传递以及它们将如何实现目标,因为所有检索器都应该能够表现出类似的行为。您也可以使用抽象类来实现此功能,但这样做会限制您基于类的祖先而不是其能力。


6

多重继承 vs 单一继承:

  • 你只能从一个抽象类中继承
  • 你可以实现多个接口

实现:

  • 抽象类可以包含实际的代码。这使得你可以在子类之间共享实现。
  • 接口仅定义公共成员函数。实现相同接口的类实际上并不共享代码。

这就是我记得的内容。


2
我听过的最好的比喻是抽象类是一个“半成品的类”。它还没有完成,你仍然需要完成它。因此,当你创建一个扩展自抽象类的类时,你只是在完成你在抽象类中开始的事情。这也是为什么你不能实例化一个抽象类的原因;因为你将它标记为抽象,表示它还不完整。它仍然需要一些额外的功能。
接口只是保证某个类中必须存在带有指定数量参数的某些方法。因此,日后使用实现特定接口的类的程序员可以放心地调用该类上的某些方法。

1
"An Abstract Class can contain default Implementation, where as an 
Interface should not contain any implementation at all. "

关于在实际应用中使用哪种语言,这真的取决于上下文。

例如,这里有一个问题,关于如何使用PHP实现游戏。在这里,他们定义了一个抽象类来定义怪物,任何怪物都可以基于这个抽象类。这允许默认怪物属性的继承。

而对于接口,您正在定义一种“接口”的通用要求(请原谅我在解释中使用该术语)。我最近做的一个项目就是实现了一个php中的soapclient,以与第三方的soapserver进行交互。此接口定义了服务器支持的soap方法,因此实现我的接口的任何类都必须定义这些方法。



1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接