根据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";
答案 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。