PHP 抽象类用 abstract class Name 声明,不能用 new 创建。它是其他类的基类:可以有属性、构造函数和完整的方法,还可以有没有方法体的 abstract 方法,每个子类都必须实现它们。
<?php
abstract class Shape
{
public function __construct(protected string $label) {}
abstract public function area(): float;
public function describe(): string
{
return sprintf('%s: %.2f', $this->label, $this->area());
}
}
class Rectangle extends Shape
{
public function __construct(private float $w, private float $h)
{
parent::__construct('Rectangle');
}
public function area(): float
{
return $this->w * $this->h;
}
}
class Circle extends Shape
{
public function __construct(private float $r)
{
parent::__construct('Circle');
}
public function area(): float
{
return M_PI * $this->r ** 2;
}
}
foreach ([new Rectangle(3, 4), new Circle(1.5)] as $shape) {
echo $shape->describe(), "\n";
}
PHP Fatal error: Class Square contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (Shape::area) in /home/index.php on line 3
模板方法模式
编写抽象类最常见的原因:一组固定顺序的步骤,其中少数几步各不相同。基类用一个 final 方法掌控整个顺序,子类负责填写各个步骤。下面同一份报表分别以纯文本和 HTML 表格的形式输出:
<?php
abstract class Report
{
public function __construct(protected array $rows) {}
final public function render(): string
{
$out = $this->open();
foreach ($this->rows as $row) {
$out .= $this->row($row);
}
return $out . $this->close();
}
abstract protected function row(array $row): string;
protected function open(): string { return ''; }
protected function close(): string { return ''; }
}
class TextReport extends Report
{
protected function row(array $row): string
{
return str_pad($row[0], 10) . $row[1] . "\n";
}
}
class HtmlReport extends Report
{
protected function open(): string { return "<table border=\"1\">\n"; }
protected function close(): string { return "</table>\n"; }
protected function row(array $row): string
{
return '<tr><td>' . htmlspecialchars($row[0]) . '</td><td>' . $row[1] . "</td></tr>\n";
}
}
$rows = [['Apples', 12], ['Pears', 7], ['Plums', 30]];
echo (new HtmlReport($rows))->render();
echo '<pre>' . (new TextReport($rows))->render() . '</pre>';
<?php
interface Cache
{
public function get(string $key): mixed;
public function set(string $key, mixed $value): void;
public function has(string $key): bool;
}
abstract class BaseCache implements Cache
{
// has() is written once, in terms of get()
public function has(string $key): bool
{
return $this->get($key) !== null;
}
}
class ArrayCache extends BaseCache
{
private array $items = [];
public function get(string $key): mixed
{
return $this->items[$key] ?? null;
}
public function set(string $key, mixed $value): void
{
$this->items[$key] = $value;
}
}
$cache = new ArrayCache();
$cache->set('user:1', 'Ada');
var_dump($cache->has('user:1'), $cache->has('user:2'));
var_dump($cache instanceof Cache);