PHP 抽象类完全指南(含 PHP 8.4 新特性)
------ 用"合同"和"模板"来理解抽象机制
本文用"公司制度""合同条款"等比喻,帮你彻底理解抽象类、抽象方法、抽象属性,适合复习和深入掌握。
一、什么是"抽象类"?------ 它是个"模板",不是"实体"
🧩 比喻:公司总部的"制度模板"
想象你是一家连锁店的总部,你不能直接"开店",但你可以制定一套 开店模板:
- 必须有店名
- 必须有营业时间
- 必须实现"开门""关门"动作
这个"模板"就是 抽象类(abstract class) 。
csharp
abstract class 店铺 {
// 这个类不能直接 new!
// 它只是一个"模板"
}
✅ 抽象类不能被实例化 (不能
new
),只能被继承。
二、抽象方法:只规定"做什么",不管"怎么做"
📝 比喻:合同里的"必须做的事"
总部规定:每家分店必须实现"开门"和"关门":
php
abstract class 店铺 {
// 只写"要做什么",不写"怎么做"
abstract public function 开门();
abstract public function 关门();
}
🔑 抽象方法的特点:
- 没有
{}
花括号,没有实现 - 必须是
public
或protected
- 子类必须实现它
✅ 子类必须"履约":
scala
class 咖啡店 extends 店铺 {
public function 开门() {
echo "打开咖啡机,播放音乐\n";
}
public function 关门() {
echo "关闭设备,锁门\n";
}
}
❌ 如果你不实现
开门()
,PHP 会报错:
csharpClass 咖啡店 contains abstract method 开门 and must therefore be abstract
三、PHP 8.4 新特性:抽象属性(abstract properties)
这是 PHP 8.4 最大的新功能之一!
🎯 问题来了:以前只能抽象"方法",不能抽象"属性"
以前你只能规定"要有开门动作",但不能规定"必须有店名"。
现在可以了!
📌 抽象属性:规定"必须有某个属性",并可要求"如何读写"
比喻:合同里规定"每家店必须有店名,并且只能读不能改"
csharp
abstract class 店铺 {
// 新语法!PHP 8.4
abstract public string $店名;
abstract protected int $编号;
}
✅ 含义:
- 所有继承
店铺
的子类,必须有一个public string $店名
- 必须有一个
protected int $编号
✅ 子类必须"提供"这些属性
scala
class 咖啡店 extends 店铺 {
public string $店名 = "星巴克";
protected int $编号 = 1001;
// ✅ 满足了抽象属性的要求
}
❌ 如果你不写
$店名
,PHP 会报错!
四、更高级:抽象属性可以要求"读"或"写"行为
🎯 场景:我想规定"$价格
可以读,但不能改"(只读),或者"$销量
只能改,不能看"(只写)
PHP 8.4 支持用 get/set 要求 来定义抽象属性。
csharp
abstract class 商品 {
// 要求子类提供一个"可读"的 $价格
abstract public readonly float $价格;
// 要求子类提供一个"可写"的 $折扣(但不关心能不能读)
abstract public writeonly float $折扣;
// 要求子类提供一个完整的 $库存(可读可写)
abstract public int $库存;
}
✅ 子类可以用多种方式"履约"
scala
class 咖啡 extends 商品 {
// ✅ 用普通属性满足"只读价格"
public readonly float $价格 = 30.0;
// ✅ 用普通属性满足"只写折扣"
private float $折扣内部;
public writeonly float $折扣 {
set { $this->折扣内部 = $value; }
}
// ✅ 用完整属性满足"库存"
public int $库存 = 100;
}
✅ 也可以用"挂钩属性"(用
get
/set
块)来实现。
五、protected 抽象属性的灵活性
📌 规则:
protected
抽象属性,可以用protected
或public
属性来满足。
scala
abstract class 父类 {
abstract protected string $秘密;
}
class 子类 extends 父类 {
public string $秘密 = "我是公开的秘密"; // ✅ 允许!
}
✅ 为什么允许?
public
比protected
更开放,满足"至少能被子类访问"的要求。- 但反过来不行:不能用
private
满足protected
。
六、抽象类中可以有"具体实现"吗?
✅ 可以! 抽象类不是"全抽象",它是"混合体"。
php
abstract class 店铺 {
abstract public string $店名;
// ✅ 可以有具体方法(普通方法)
public function 打印信息() {
echo "欢迎光临{$this->店名}!\n";
}
// ✅ 可以有普通属性
protected int $访客数 = 0;
abstract public function 开门();
}
🔑 抽象类 = 抽象 + 具体 的混合体,像个"半成品模板"。
七、总结:一张表讲清抽象机制
类型 | 语法 | 子类必须实现? | 说明 |
---|---|---|---|
抽象类 | abstract class A |
❌ 不能实例化 | 只能被继承 |
抽象方法 | abstract public function foo(); |
✅ 必须实现 | 无方法体 |
抽象属性 | abstract public string $name; |
✅ 必须提供 | PHP 8.4 新增 |
只读抽象属性 | abstract public readonly int $id; |
✅ | 要求属性可读 |
只写抽象属性 | abstract public writeonly float $discount; |
✅ | 要求属性可写 |
✅ 生活化口诀(终极记忆法)
"抽象类 = 合同模板"
"抽象方法 = 必须做的事"
"抽象属性 = 必须有的东西"
"谁继承,谁履约;少一样,就报错!"
📚 一句话回答你的问题
"抽象属性 "是 PHP 8.4 的新功能,它允许你在一个抽象类中声明某个属性必须存在 ,并可以规定它是
public
还是protected
,甚至可以要求它是 只读(readonly) 或 只写(writeonly) 。子类必须用标准属性 或挂钩属性来"满足"这些要求,就像"履约"一样。