请解释一下什么时候我应该使用PHP接口,什么时候我应该使用抽象类?

我如何能改变我的抽象类在一个接口?


当前回答

抽象类和接口的区别:

抽象类

抽象类可以提供一些功能,而将其余的功能留给派生类。

派生类可以重写基类中定义的具体函数,也可以不重写。 从抽象类扩展而来的子类在逻辑上应该是相关的。

接口

接口不能包含任何功能。它只包含方法的定义。

派生类必须为接口中定义的所有方法提供代码。 完全不同且不相关的类可以使用接口在逻辑上分组在一起。

其他回答

为什么要使用抽象类?下面是一个简单的例子。假设我们有以下代码:

<?php 

class Fruit {
    private $color;

    public function eat() {
        // chew
    }

    public function setColor($c) {
        $this->color = $c;
    }
}

class Apple extends Fruit {
    public function eat() {
        // chew until core
    }
}

class Orange extends Fruit {
    public function eat() {
        // peeling
        // chew
    }
}

现在我给你一个苹果,你吃了它。 它尝起来像什么?它尝起来像苹果。

<?php 
$apple = new Apple();
$apple->eat();

// Now I give you a fruit.
$fruit = new Fruit();
$fruit->eat();

那是什么味道?这没什么意义,所以你不能这么做。这是通过使Fruit类抽象以及其中的eat方法来实现的。

<?php 
abstract class Fruit {
    private $color;

    abstract public function eat(){}

    public function setColor($c) {
        $this->color = $c;
    }
}
?>

一个抽象类就像一个接口,但是你可以在一个抽象类中定义方法,而在一个接口中它们都是抽象的。抽象类可以有空方法和工作/具体方法。在接口中,定义的函数不能有主体。在抽象类中,它们可以。

一个真实的例子:

<?php 
abstract class person {

    public $LastName;
    public $FirstName;
    public $BirthDate;

    abstract protected function write_info();
}

final class employee extends person{

    public $EmployeeNumber;
    public $DateHired;

    public function write_info(){
        //sql codes here
        echo "Writing ". $this->LastName . "'s info to emloyee dbase table <br>";   
    }
}

final class student extends person{

    public $StudentNumber;
    public $CourseName;

    public function write_info(){
        //sql codes here
        echo "Writing ". $this->LastName . "'s info to student dbase table <br>";
    }
}

///----------
$personA = new employee;
$personB = new student;

$personA->FirstName="Joe";
$personA->LastName="Sbody";

$personB->FirstName="Ben";
$personB->LastName="Dover";

$personA->write_info();
// Writing Sbody's info to emloyee dbase table
$personB->write_info();
// Writing Dover's info to student dbase table 

抽象类和接口的区别:

抽象类

抽象类可以提供一些功能,而将其余的功能留给派生类。

派生类可以重写基类中定义的具体函数,也可以不重写。 从抽象类扩展而来的子类在逻辑上应该是相关的。

接口

接口不能包含任何功能。它只包含方法的定义。

派生类必须为接口中定义的所有方法提供代码。 完全不同且不相关的类可以使用接口在逻辑上分组在一起。

当您希望强制在您的系统中工作的开发人员(包括您自己)在他们将要构建的类上实现一组方法时,请使用接口。

当你想强迫在你的系统中工作的开发人员(包括你自己)实现一组方法,并且你想提供一些基本方法来帮助他们开发他们的子类时,使用抽象类。

另一件需要记住的事情是客户端类只能扩展一个抽象类,而它们可以实现多个接口。因此,如果您在抽象类中定义行为契约,这意味着每个子类可能只符合一个契约。有时这是一件好事,当你想强迫你的用户程序员沿着特定的路径。其他时候就不好了。想象一下,如果PHP的Countable和Iterator接口是抽象类而不是接口。

当您不确定该走哪条路时(如下面的cletus所述),一种常见的方法是创建一个接口,然后让抽象类实现该接口。

主要的区别是抽象类可以包含默认实现,而接口不能。

接口是没有任何实现的行为契约。

只是把这一点加入到混合中,但正如Cletus提到的将接口与抽象类结合使用一样,我经常使用接口来阐明我的设计思维。

例如:

<?php
class parser implements parserDecoratorPattern {
    //...
}

这样,任何阅读我的代码(并且知道Decorator Pattern是什么)的人都将立即知道a)我如何构建我的解析器和b)能够看到使用哪些方法来实现Decorator模式。

此外,我可能不是Java/ c++ /等程序员,但数据类型可以在这里发挥作用。你的对象是一个类型,当你传递它们时,类型在编程上很重要。将可收缩项移动到接口中只指定方法返回的类型,但不指定实现它的类的基类型。

现在已经很晚了,我想不出一个更好的伪代码示例,但如下所示:

<?php
interface TelevisionControls {};
class Remote implements TelevisionControls {};
class Spouse implements TelevisionControls {};
Spouse spouse = new Spouse();
Remote remote = new Remote();
isSameType = (bool)(remote == spouse)