PHP 简明教程

PHP 抽象类

1. 什么是抽象类和抽象方法?

抽象类和抽象方法是指父类知道子类应该具备哪些功能,但具体如何实现这些功能则由子类自行决定。

抽象类是指包含至少一个抽象方法的类。而抽象方法是指只声明了函数签名,但没有具体代码实现的函数。

在 PHP 中,使用 abstract 关键字来定义抽象类或抽象方法:

abstract class ParentClass {
  abstract public function someMethod1();
  abstract public function someMethod2($name, $color);
  abstract protected function someMethod3() : string;
}

当从一个抽象类继承时,子类方法必须遵循以下规则:

  • 子类必须实现父类中所有的抽象方法。
  • 子类方法的访问修饰符必须与父类一致,或者更加宽松。例如,如果父类方法是 protected,子类可以定义为 protectedpublic,但不能是 private
  • 方法的参数数量和类型必须匹配。不过,子类可以包含额外的可选参数。

2. PHP 抽象类示例

让我们看一个例子:父类 Car 是一个抽象类。它有一个抽象方法 intro()AudiVolvoCitroenCar 的子类,它们都必须实现 intro() 方法。

代码示例:

<?php
// 父类
abstract class Car {
  public $name;
  public function __construct($name) {
    $this->name = $name;
  }
  abstract public function intro() : string;
}

// 子类
class Audi extends Car {
  public function intro() : string {
    return "选择德国品质!我是 {$this->name}!";
  }
}

class Volvo extends Car {
  public function intro() : string {
    return "安全第一!我是 {$this->name}!";
  }
}

class Citroen extends Car {
  public function intro() : string {
    return "法国设计!我是 {$this->name}!";
  }
}

// 创建子类对象
$audi = new Audi("Audi");
echo $audi->intro();
echo "<br>";

$volvo = new Volvo("Volvo");
echo $volvo->intro();
echo "<br>";

$citroen = new Citroen("Citroen");
echo $citroen->intro();
?>

2.1 示例解析

在上述代码中:

  1. Car 类是一个抽象类,这意味着你不能直接创建它的实例(即不能 $myCar = new Car())。
  2. 它强制所有子类必须提供 intro() 方法的逻辑。
  3. 每个子类根据自身的品牌特性,返回了不同的字符串。

2.2 更多示例

抽象方法也可以带有参数。在实现时,子类必须保证参数定义的一致性。

代码示例:

<?php
abstract class ParentClass {
  // 带有参数的抽象方法
  abstract protected function prefixName($name);
}

class ChildClass extends ParentClass {
  public function prefixName($name) {
    if ($name == "John Doe") {
      $prefix = "Mr.";
    } elseif ($name == "Jane Doe") {
      $prefix = "Mrs.";
    } else {
      $prefix = "";
    }
    return "{$prefix} {$name}";
  }
}

$class = new ChildClass;
echo $class->prefixName("John Doe");
echo "<br>";
echo $class->prefixName("Jane Doe");
?>

2.3 另一个示例

如果子类在实现抽象方法时增加了额外的参数,只要这些参数带有默认值(即可选参数),程序依然可以正常运行。

代码示例:

<?php
abstract class ParentClass {
  abstract protected function prefixName($name);
}

class ChildClass extends ParentClass {
  // 子类定义了比父类更多的参数 ($separator, $greet)
  // 但因为它们有默认值,所以符合继承规范
  public function prefixName($name, $separator = ".", $greet = "Dear") {
    if ($name == "John Doe") {
      $prefix = "Mr";
    } elseif ($name == "Jane Doe") {
      $prefix = "Mrs";
    } else {
      $prefix = "";
    }
    return "{$greet} {$prefix}{$separator} {$name}";
  }
}

$class = new ChildClass;
echo $class->prefixName("John Doe");
echo "<br>";
echo $class->prefixName("Jane Doe");
?>

什么时候使用抽象类?
当你想要创建一个基类,但这个基类本身并不代表一个具体的实体(例如“动物”是一个抽象概念,而“猫”是具体的),并且你希望强制所有的子类都遵循某种特定的接口规范时,抽象类是最佳选择。