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

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


当前回答

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

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

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

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

其他回答

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

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

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

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

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

<?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 

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

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

抽象类和接口的区别:

抽象类

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

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

接口

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

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

只是想添加一个例子,说明什么时候你可能需要使用这两种方法。我目前正在编写一个通用ERP解决方案中绑定到数据库模型的文件处理程序。

我有多个抽象类,处理标准的crud,也有一些特殊的功能,如转换和流的不同类别的文件。 文件访问接口定义了一组用于获取、存储和删除文件的通用方法。

通过这种方式,我可以为不同的文件拥有多个模板,以及一组具有明显区别的公共接口方法。接口对访问方法进行了正确的类比,而不是对基抽象类的类比。

接下来,当我将为不同的文件存储服务制作适配器时,这种实现将允许在完全不同的上下文中在其他地方使用接口。