简体   繁体   English

PHP:抽象类的用例是什么

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

As per php.net documentation : 根据php.net文档:

When inheriting from an abstract class, all methods marked abstract in the parent's class declaration must be defined by the child; 从抽象类继承时,父类声明中标记为abstract的所有方法都必须由子类定义; additionally, these methods must be defined with the same (or a less restricted) visibility. 此外,必须使用相同(或限制较少)的可见性来定义这些方法。 For example, if the abstract method is defined as protected, the function implementation must be defined as either protected or public, but not private. 例如,如果将抽象方法定义为protected,则必须将函数实现定义为protected或public,而不是private。 Furthermore the signatures of the methods must match, ie the type hints and the number of required arguments must be the same. 此外,方法的签名必须匹配,即类型提示和所需参数的数量必须相同。 For example, if the child class defines an optional argument, where the abstract method's signature does not, there is no conflict in the signature. 例如,如果子类定义了一个可选参数,而抽象方法的签名没有,则签名中不存在冲突。 This also applies to constructors as of PHP 5.4. 这也适用于PHP 5.4的构造函数。 Before 5.4 constructor signatures could differ. 在5.4构造函数签名可能不同之前。

In php.net they have shown the following example: 在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";

If I run this I get the below output: 如果我运行这个,我得到以下输出:

ConcreteClass1 FOO_ConcreteClass1 ConcreteClass2 FOO_ConcreteClass2

Reading the documentation, my initial understanding was "parent classes in general can not access methods from their children if they are extend" and that's why we need abstract classes. 阅读文档,我最初的理解是“一般来说,父类不能访问子项中的方法,如果它们是扩展的”,这就是我们需要抽象类的原因。 However, when I tried the same example above with a little bit of tweak, removing all the abstractions (given below) I see the exact same output as the previous example. 但是,当我尝试上面的相同示例并进行一些调整时,删除所有抽象(如下所示),我看到与前一个示例完全相同的输出。 Therefore, why do we need abstract classes in PHP. 因此,为什么我们需要PHP中的抽象类。 Only use case I found is while implementing an interface in the parent class; 我发现的唯一用例是在父类中实现接口时; I get error if I do not declare the parent as abstract. 如果我不将父类声明为抽象,我会收到错误。 Is there other cases where I must or it is highly recommended to use abstract class? 是否有其他情况我必须或强烈建议使用抽象类?

//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";

If I have a group of similar things, let's say furniture. 如果我有一组类似的东西,让我们说家具。

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

And so on. 等等。 But "Furniture" is an abstract concept. 但“家具”是一个抽象的概念。 It is not, itself, a thing the way "Chair" and "Table" are. 这不是本身的事情 。“主席”和“表”的方式。 Therefore, it would be best to define: 因此,最好定义:

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

It's always a good idea to think of classes as "types of thing". 将类视为“事物的类型”总是一个好主意。 Some are concrete, like chairs and tables, and others are abstract, like furniture. 有些是混凝土,如椅子和桌子,有些是抽象的,如家具。

The point is, it makes no sense to have new Furniture() in your code, because furniture should be a specific kind. 关键是,在您的代码中使用new Furniture()是没有意义的,因为家具应该是特定的类型。 Using abstract class disallows new Furniture() and acts as a sanity check. 使用abstract class不允许使用new Furniture()并充当健全性检查。

However, when I tried the same example above with a little bit of tweak, removing all the abstractions (given below) I see the exact same output as the previous example. 但是,当我尝试上面的相同示例并进行一些调整时,删除所有抽象(如下所示),我看到与前一个示例完全相同的输出。

PHP is dynamically typed so the parent class can access methods that 'may or may not exist' 1 ; PHP是动态类型的,因此父类可以访问“可能存在或不存在”的方法1 ; the same polymorphism still holds (for non-private methods). 相同的多态性仍然存在(对于非私有方法)。 In a languages like Java or C#, the code would have failed to compile. 在Java或C#等语言中,代码无法编译。 (Interface/contract checking is a separate issue 2 .) (接口/合同检查是一个单独的问题2.

Thus both examples are technically valid in PHP and will produce the same output, without error or warning. 因此,这两个示例在PHP中在技术上都是有效的,并且将产生相同的输出,没有错误或警告。

Is there other cases where I must or it is highly recommended to use [abstract methods]? 是否有其他情况我必须或强烈建议使用[抽象方法]?

It is 'more correct' when applying nominative types / class declarations to annotate the method as abstract as this: 当应用主格类型/类声明来将方法注释为抽象时,它更“正确”

  • Establishes a guarantee that an implementation is provided by concrete subclasses 2 建立一个实现具体的子类提供了保障2

  • Provides additional information for type-checking tools; 提供类型检查工具的附加信息; and is a safeguard if stricter type checking is applied in the future 如果将来采用更严格的类型检查,这是一种保障

  • Declares a method signature and documentation stub; 声明方法签名和文档存根; and appears in type reflection 并出现在反射类型中

The linked example/documentation already explain the semantic goal of abstract methods. 链接的示例/文档已经解释了抽象方法的语义目标。 (However it is fraught with some .. questionable wording; eg. private methods cannot be abstract .) (但它充满了一些......有问题的措辞;例如, 私人方法不能抽象 。)


1 This is also known as duck typing and is allowed in many other dynamic languages - including Ruby, Python, and JavaScript - which support OO and and the same concept of abstract methods, albeit less formally, as expressed through subtype polymorphism . 1这也被称为鸭子打字 ,并且允许在许多其他动态语言中使用 - 包括Ruby,Python和JavaScript - 它们支持OO和抽象方法的相同概念,尽管不那么正式,通过子类型多态性表达。

2 Interface/contract checking (which is only done for type definitions) ensures that the implementing class, or subclass for abstract classes, must conform to the specified types. 2接口/协定检查(仅对类型定义进行检查)确保实现类或抽象类的子类必须符合指定的类型。 In the case of abstract methods this means that subclasses must provide method implementations or be abstract themselves . 在抽象方法的情况下,这意味着子类必须提供方法实现或者本身是抽象的

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

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