## 抽象类

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

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

自 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;
}
?>`

抽象类上的抽象属性可以为任何挂钩提供实现，必须声明 `get` 或 `set` 但是没有定义（如上例所示）。

示例 #4 带有挂钩的抽象属性示例

`<?php
abstract class A
{
// 这提供了默认（但可覆盖）set 实现，
// 并要求子类提供 get 实现
abstract public string $foo {
get;
set {
$this->foo = $value;
}
}
}
?>`
`↑` and `↓` to navigate • `Enter` to select • `Esc` to close • `/` to open