PHP:抽象类的用例是什么
根据php.net文档: 从抽象类继承时,父类声明中标记为抽象的所有方法必须由子类定义;此外,这些方法必须以相同(或限制较少)的可见性定义。例如,如果抽象方法定义为protected,则函数实现必须定义为protected或public,而不是private。此外,方法的签名必须匹配,即类型提示和所需参数的数量必须相同。例如,如果子类定义了可选参数,而抽象方法的签名没有,则签名中没有冲突。这也适用于PHP5.4中的构造函数。在5.4之前,构造函数签名可能会有所不同 在php.net中,他们展示了以下示例:PHP:抽象类的用例是什么,php,Php,根据php.net文档: 从抽象类继承时,父类声明中标记为抽象的所有方法必须由子类定义;此外,这些方法必须以相同(或限制较少)的可见性定义。例如,如果抽象方法定义为protected,则函数实现必须定义为protected或public,而不是private。此外,方法的签名必须匹配,即类型提示和所需参数的数量必须相同。例如,如果子类定义了可选参数,而抽象方法的签名没有,则签名中没有冲突。这也适用于PHP5.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
}
把类看作“事物的类型”总是一个好主意。有些是具体的,像椅子和桌子,还有一些是抽象的,像家具
class Chair extends Furniture {
// define methods to handle being sat on
}
class Table extends Furniture {
// define methods to handle holding things up
}
关键是,在代码中添加新家具()
是没有意义的,因为家具应该是一种特定的类型。使用抽象类
不允许新建家具()
,并充当健全性检查
然而,当我尝试上面的同一个示例时,稍微做了一些调整,删除了所有的抽象(如下所示),我看到的输出与前面的示例完全相同
PHP是动态类型化的,因此父类可以访问“可能存在也可能不存在”的方法1;同样的多态性仍然适用(对于非私有方法)。在Java或C#等语言中,代码可能无法编译。(接口/合同检查是一个单独的问题2。)
因此,这两个示例在PHP中在技术上都是有效的,并且将生成相同的输出,没有错误或警告
是否有其他情况我必须使用或强烈建议使用[抽象方法]
当应用命名类型/类声明将方法注释为抽象时,“更正确”,如下所示:
- 建立一个保证,保证实现由具体的子类2提供
- 提供类型检查工具的附加信息;如果将来应用更严格的类型检查,这是一种保障
- 声明方法签名和文档存根;并出现在类型反射中
1这也被称为duck类型,在许多其他动态语言中都是允许的,包括Ruby、Python和JavaScript,这些语言支持OO和相同的抽象方法概念,尽管形式上不太正式,但通过子类型多态性表示
2接口/契约检查(仅针对类型定义进行)确保实现类或抽象类的子类必须符合指定的类型。在抽象方法的情况下,这意味着子类必须提供方法实现。如果是这样,那么所有抽象类都是关于
类家具{protectedfunction\uu construct(){}
就可以了;-)当//定义适用于各种家具的方法时,抽象类是有意义的
是大量代码(或高度重复的代码),这些代码在抽象概念上工作,但需要具体的实现+在实例的状态下工作,您不必向外界公开(在这种情况下,您可以在不同的类中将数据与策略分开).@Niet the Dark Absol,谢谢你的回答。我相信这对很多人都有帮助。但是,我的问题不是一般的抽象类。在我的问题中,我演示了,我们使用抽象所做的事情可以使用简单的类扩展来完成。因此,我想知道什么是“特殊的”关于抽象类?@user3360140我有点认为它与类型暗示相同(function foo(Bar$baz)
)-它本身没有什么不同,没有它你也可以过得很好,但它提供了一个内置的健全性检查,而不是“不允许在抽象类上实例化”。