封装解决“谁能看到、谁不能改”的权限问题,靠private/protected/public实现;抽象类解决“子类必须实现哪些行为”的结构约束问题,靠abstract关键字和未实现方法强制规范。

封装是访问控制,抽象类是设计契约
封装解决的是“谁能看到、谁不能改”的权限问题,靠 private、protected、public 实现;抽象类解决的是“子类必须实现哪些行为”的结构约束问题,靠 abstract 关键字和未实现的方法定义来强制规范。
两者常一起用,但目的完全不同:你可以在一个抽象类里把属性设为 private(封装),同时声明一个 abstract public function render()(契约)——前者防误改,后者保接口统一。
抽象类天然依赖封装机制才能成立
如果抽象类里的方法或属性不加访问控制,子类可能绕过设计意图直接操作内部状态,导致契约失效。比如:
-
abstract class PaymentGateway声明了abstract protected function validate(),但若把核心校验逻辑放在public $config里,子类就能随意覆盖,等于白定义 - 子类重写
process()时,若能直接读写父类的$connection(本该是protected),就破坏了封装边界,也削弱了抽象类对流程控制的约束力
常见混淆点:abstract 不等于 private
很多人以为“抽象方法不能被调用”所以等同于私有,这是错的。抽象方法是 public 或 protected 的,默认就是 public,它只是没函数体。关键区别在于:
-
private方法子类根本看不到,也不能继承 -
abstract protected function init()子类必须实现,且只能在自身或父类作用域内调用,这正是封装 + 抽象的协同体现 - 如果把抽象方法写成
private abstract function xxx(),PHP 会直接报错:Cannot make static method private(实际错误是Access level to ... must be public or protected)
什么时候该用抽象类而不是普通类+封装
当你要表达“这一类东西必须有 X 行为,但具体怎么做由子类决定”,且这些子类共享部分通用逻辑或状态时。例如:
- 多个日志驱动(
FileLogger、DbLogger、SyslogLogger)都需实现write(),但共用$level和formatMessage() - 如果只靠封装,你无法强制子类实现
write();如果不用抽象类,你就得靠文档或运行时报错提醒,失去编译期约束 - 此时抽象类提供骨架,封装确保骨架里的字段不被外部篡改,二者缺一不可
真正容易被忽略的是:抽象类本身不能 new,但它里面的 protected 属性和非抽象方法,是子类可继承、可复用、但不可对外暴露的——这个边界感,得靠封装来守住。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











