PHP接口和抽象类继承的最佳实践?

时间:2013-12-06 23:53:39

标签: php inheritance abstract-class implementation

在定义结构并继承Interface和/或Abstract Class时,哪一个是最佳实践?为什么?以下是两个例子:

以下是[界面]的示例 - > [摘要类] - > [类别]

Interface DataInterface
{
    public function __construct($connection);
    public function connected();
    public function get();
}

Abstract class BaseData implements DataInterface
{
    protected $connection;

    public function __construct($connection)
    {
        $this->connection = $connection;
    }
}


class UserData extends BaseData
{
    public function exists()
    {
        return is_connected($this->connection);
    }

    public function get()
    {
        return get_data($this->connection);
    }
}

$oUserData = new UserData(new Connection());

以下是[Abstract Class]的样本 - >没有接口的[类]

Abstract class BaseData
{
    protected $connection;

    public function __construct($connection)
    {
        $this->connection = $connection;
    }

    abstract public function connected();
    abstract public function get();
}

class UserData extends BaseData
{
    public function exists()
    {
        return is_connected($this->connection);
    }

    public function get()
    {
        return get_data($this->connection);
    }
}

$oUserData = new UserData(new Connection());

我目前正在创建一个小应用程序(可能会变得更大)并且对如何在开头正确实施感到困惑。

顺便说一下,带参数的__construct()的声明是否在Interface?

中有意义
public function __construct($connection);

3 个答案:

答案 0 :(得分:9)

抽象类定义了必须对抽象类的继承人实现的接口。 Interface-Construct定义了一个必须由实现interface-construct的类实现的接口,接口的实现不仅限于单个接口,而类继承则耦合到单个(抽象)类。

PHP中的接口有意用于允许整个类接口的有限子集的类型提示。没有理由在抽象类上使用接口,因为他们的继承者实例的接收者没有使用它们(在instanceof / is_a上使用typehinting或逻辑标识)。接口构造的更有价值的好处是可以用替代实现替换接口的通用实现。

如果你的BaseData-Example,我建议删除抽象的想法并使用特征和单独的接口。

trait connectionBrokerConstructor {
    protected $connection;

    public function isConnected()
    {
        return $this->connection instanceof Connection;
    }

    public function setConnection(Connection $connection)
    {
        $this->connection = $connection;
    }
}

interface connectable
{
    public function setConnection(Connection $connection);
    public function isConnected();
}

interface userDataRepositoryInterface
{
    public function get();
}

class UserData implements connectable, userDataRepositoryInterface
{
    use connectionBrokerConstructor;

    public function __construct(Connection $connect = null)
    {
        $this->setConnection($connection);
    }

    public function get()
    {
        return array('something');
    }
}

答案 1 :(得分:2)

真正抽象的类和接口是不同的。

将接口视为契约,它规定了其他类(实现它)必须遵循的规则。

另一方面,抽象类更像是起点,其他类可以构建,因此它们有时被称为基类。

-------用示例编辑

我不是这方面的专家,但我一直都在做interface - > class

例如,这是一个简单的界面:

interface AnimalInterface {

  public function all();

  public function findBySlug($slug);

}

这是实现该接口的类(简化):

class AnimalEloquentRepository implements AnimalInterface {

  public function all()
  {
    return Animal::all();
  }

  public function findBySlug($slug)
  {
    return Animal::whereSlug($slug)->first();
  }

}

我经常有一个基类,其他人扩展,但我只在真实世界的应用程序中使用了一个抽象类,最终被替换。

我确信有更好的方法可以做,但过去这对我来说非常有效。

答案 2 :(得分:0)

我的声誉不允许发表评论,但tr0y的答案中的这句话具有误导性:

“抽象类定义了一个必须对抽象类的继承人实现的接口。”

接口和抽象类之间的主要区别之一是,在扩展的类中实现任何抽象类方法所需的 它。抽象类通常具有默认行为的方法,并且如果默认行为不是您想要的,则仅在继承人中提供这些方法。

另一方面, 要求在任何实现该接口的类中创建所有方法。

另一个区别是接口中的方法不能有主体,而抽象类中的方法必须有主体。