抽象类

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;
        }
    }
}

?>