PHP:抽象类的用例是什么

时间:2015-09-16 23:58:13

标签: php

根据php.net文档:

  

当从抽象类继承时,父类的声明中标记为abstract的所有方法都必须由子类定义;此外,必须使用相同(或限制较少)的可见性来定义这些方法。例如,如果将抽象方法定义为protected,则必须将函数实现定义为protected或public,而不是private。此外,方法的签名必须匹配,即类型提示和所需参数的数量必须相同。例如,如果子类定义了可选参数,而抽象方法的签名没有,则签名中不存在冲突。这也适用于PHP 5.4的构造函数。在5.4构造函数签名可能不同之前。

在php.net中,他们展示了以下示例:

abstract class AbstractClass
{
    // Force Extending class to define this method
    abstract protected function getValue();
    abstract protected function prefixValue($prefix);

    // Common method
    public function printOut() {
        print $this->getValue() . "\n";
    }
}

class ConcreteClass1 extends AbstractClass
{
    protected function getValue() {
        return "ConcreteClass1";
    }

    public function prefixValue($prefix) {
        return "{$prefix}ConcreteClass1";
    }
}

class ConcreteClass2 extends AbstractClass
{
    public function getValue() {
        return "ConcreteClass2";
    }

    public function prefixValue($prefix) {
        return "{$prefix}ConcreteClass2";
    }
}

$class1 = new ConcreteClass1;
$class1->printOut();
echo $class1->prefixValue('FOO_') ."\n";

$class2 = new ConcreteClass2;
$class2->printOut();
echo $class2->prefixValue('FOO_') ."\n";

如果我运行这个,我得到以下输出:

ConcreteClass1 FOO_ConcreteClass1 ConcreteClass2 FOO_ConcreteClass2

阅读文档,我最初的理解是#34;父类通常无法访问子项中的方法,如果它们是扩展的"这就是为什么我们需要抽象类。但是,当我尝试上面的相同示例并进行一些调整时,删除所有抽象(如下所示),我看到与前一个示例完全相同的输出。因此,为什么我们需要PHP中的抽象类。我发现的唯一用例是在父类中实现接口时;如果我不将父类声明为抽象,我会收到错误。是否有其他情况我必须或强烈建议使用抽象类?

//abstract
class AbstractClass
{
    // Force Extending class to define this method
    //abstract protected function getValue();
    //abstract protected function prefixValue($prefix);

    // Common method
    public function printOut() {
        print $this->getValue() . "\n";
    }
}

class ConcreteClass1 extends AbstractClass
{
    protected function getValue() {
        return "ConcreteClass1";
    }

    public function prefixValue($prefix) {
        return "{$prefix}ConcreteClass1";
    }
}

class ConcreteClass2 extends AbstractClass
{
    public function getValue() {
        return "ConcreteClass2";
    }

    public function prefixValue($prefix) {
        return "{$prefix}ConcreteClass2";
    }
}

$class1 = new ConcreteClass1;
$class1->printOut();
echo $class1->prefixValue('FOO_') ."\n";

$class2 = new ConcreteClass2;
$class2->printOut();
echo $class2->prefixValue('FOO_') ."\n";

2 个答案:

答案 0 :(得分:4)

如果我有一组相似的东西,那就说家具。

class Chair extends Furniture {
    // define methods to handle being sat on
}
class Table extends Furniture {
    // define methods to handle holding things up
}

等等。但“家具”是一个抽象概念。它本身不是“主席”和“桌子”的方式 thing 。因此,最好定义:

abstract class Furniture {
    // define methods that apply to all kinds of furniture
}

将课程视为“事物的类型”总是一个好主意。有些是具体的,如椅子和桌子,有些是抽象的,如家具。

关键是,在代码中使用new Furniture()是没有意义的,因为家具应该是特定的类型。使用abstract class禁止new Furniture()并充当理智检查。

答案 1 :(得分:2)

  

但是,当我尝试上面的相同示例并进行一些调整时,删除所有抽象(如下所示),我看到与前一个示例完全相同的输出。

PHP是动态类型,因此父类可以访问“可能存在或不存在”的方法 1 ;相同的多态性仍然存在(对于非私有方法)。在Java或C#等语言中,代码无法编译。 (接口/合同检查是一个单独的问题 2 。)

因此,这两个示例在PHP中在技术上都是有效的,并且会生成相同的输出,而不会出现错误或警告。

  

是否有其他情况我必须或强烈建议使用[抽象方法]?

当应用主格类型/类声明来将方法注释为抽象时,它更“正确”:

  • 建立由具体子类提供的实现 的保证 2

  • 提供类型检查工具的其他信息;如果将来采用更严格的类型检查,这是一种保障措施

  • 声明方法签名和文档存根;并出现在反射类型

链接的示例/文档已经解释了抽象方法的语义目标。 (但它充满了一些......有问题的措辞;例如。private methods cannot be abstract。)

1 这也称为 duck typing ,并且允许在许多其他动态语言中使用 - 包括Ruby,Python和JavaScript - 它们支持OO和相同的概念通过子类型多态性表示的抽象方法,尽管不那么正式。

2 接口/合同检查(仅对类型定义进行)检查确保实现类或抽象类的子类必须符合指定的类型。对于抽象方法,这意味着子类必须提供方法实现or be abstract themselves

相关问题