繁体   English   中英

PHP:抽象类的用例是什么

[英]PHP: what is the use case of abstract class

根据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

阅读文档,我最初的理解是“一般来说,父类不能访问子项中的方法,如果它们是扩展的”,这就是我们需要抽象类的原因。 但是,当我尝试上面的相同示例并进行一些调整时,删除所有抽象(如下所示),我看到与前一个示例完全相同的输出。 因此,为什么我们需要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";

如果我有一组类似的东西,让我们说家具。

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

等等。 但“家具”是一个抽象的概念。 这不是本身的事情 。“主席”和“表”的方式。 因此,最好定义:

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

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

关键是,在您的代码中使用new Furniture()是没有意义的,因为家具应该是特定的类型。 使用abstract class不允许使用new Furniture()并充当健全性检查。

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

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

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

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

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

  • 建立一个实现具体的子类提供了保障2

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

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

链接的示例/文档已经解释了抽象方法的语义目标。 (但它充满了一些......有问题的措辞;例如, 私人方法不能抽象 。)


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

2接口/协定检查(仅对类型定义进行检查)确保实现类或抽象类的子类必须符合指定的类型。 在抽象方法的情况下,这意味着子类必须提供方法实现或者本身是抽象的

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM