抽象类

PHP 有抽象类、抽象方法和抽象属性。定义为抽象的类无法实例化。任何一个类,如果它里面有一个方法或者属性是声明为抽象,那么这个类就必须被声明为抽象。定义为抽象的方法仅声明方法的签名以及它是 public 还是 protected;但无法定义实现。定义为抽象的属性可以声明 getset 行为的要求,并且可以为一个(但不是全部)操作提供实现。

继承一个抽象类的时候,子类必须定义父类中的所有抽象方法, 并遵循常规的 继承 签名兼容性 规则。

自 PHP 8.4 起,抽象类可以声明抽象属性,可以是 public,也可以是 protected。protected 抽象属性可以从 protected 或 public 作用域读取/写入的属性满足。

抽象属性可以由标准属性或挂钩属性来满足,与所需的操作相对应。

示例 #1 抽象方法示例

<?php

abstract class AbstractClass
{
// 强制要求子类定义这些方法
abstract protected function getValue();
abstract protected function
prefixValue($prefix);

// 普通方法(非抽象方法)
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

示例 #2 抽象方法示例

<?php

abstract class AbstractClass
{
// 抽象方法仅需要定义需要的参数
abstract protected function prefixName($name);
}

class
ConcreteClass extends AbstractClass
{
// 子类可以定义父类签名中不存在的可选参数
public function prefixName($name, $separator = ".")
{
if (
$name == "Pacman") {
$prefix = "Mr";
} elseif (
$name == "Pacwoman") {
$prefix = "Mrs";
} else {
$prefix = "";
}

return
"{$prefix}{$separator} {$name}";
}
}

$class = new ConcreteClass();
echo
$class->prefixName("Pacman"), "\n";
echo
$class->prefixName("Pacwoman"), "\n";

?>

以上示例会输出:

Mr. Pacman
Mrs. Pacwoman

示例 #3 抽象属性示例

<?php

abstract class A
{
// 继承类必须具有可 public get 的属性
abstract public string $readable {
get;
}

// 继承类必须具有 protected 或 public set 的属性
abstract protected string $writeable {
set;
}

// 继承类必须具有 protected 或 public 的对称属性。
abstract protected string $both {
get;
set;
}
}

class
C extends A
{
// 这满足了要求,也使其可 set,这是有效的
public string $readable;

// 这不能满足要求,因为它不能 public 可读
protected string $readable;

// 这正好满足要求,所以足够了。
// 它只能被写入,并且只能从 protected 作用域进行写入。
protected string $writeable {
set => $value;
}

// 这将访问控制从 protected 继承为 public,这很好
public string $both;
}

?>

抽象类上的抽象属性可以为任何挂钩提供实现,必须声明 getset 但是没有定义(如上例所示)。

示例 #4 抽象属性示例

<?php

abstract class A
{
// 这提供了默认(但可覆盖)set 实现,
// 并要求子类提供 get 实现
abstract public string $foo {
get;

set {
$this->foo = $value;
}
}
}

?>