private属性不可被子类访问或继承,仅限本类内部使用;protected属性可被子类访问但易因耦合引发运行时错误;php 8.3起readonly属性支持继承,但须严格通过parent::__construct()初始化,否则导致不可赋值或状态腐化。

封装没做好,继承就必然失控——这不是设计风格问题,而是 PHP 运行时机制决定的硬性约束。
private 属性让子类“看不见也摸不着”
PHP 中 private 成员只在定义它的类内部可见,子类连读取都做不到,更别说重写或扩展逻辑。很多开发者误以为“父类写了属性,子类自然能用”,结果在子类里直接访问 $this->privateProp 时静默失败或报 Fatal error: Cannot access private property。
- 父类用
private $config存配置,子类想覆盖部分键?做不到,只能复制粘贴整段初始化逻辑 - 子类重写
public function save(),但内部依赖父类的private function validate()?无法调用,只能自己重写验证,重复造轮子 - 调试时 var_dump 子类实例,
private属性完全不显示,你以为字段丢了,其实是被语言规则藏起来了
protected 不等于“放心交给子类”
protected 看似开放,但一旦父类内部逻辑强耦合于这些受保护成员的结构或生命周期,子类就极易踩坑。比如父类在 __construct() 里直接给 protected $cache 赋了一个未初始化的数组,子类若在自己的构造函数里提前调用了某个依赖 $cache 的方法,就会遇到 Notice: Trying to access array offset on value of type null。
- 父类把
protected $items设为数组,子类换成ArrayObject实例?类型不一致,父类后续的count($this->items)可能崩 - 父类文档没写清
protected $state的合法值范围,子类设了个非法字符串,触发父类某处switch的 default 分支,行为不可控 - PHP 8.1+ 对继承方法返回类型开始校验,如果父类
protected function getData(): array,子类重写时返回stdClass,运行时直接抛TypeError
构造函数链断裂导致只读属性失效(PHP 8.3+)
PHP 8.3 支持继承 readonly 属性,但前提是构造函数必须显式调用 parent::__construct()。如果父类构造函数里初始化了 public readonly string $id,而子类忘了这句调用,或者用了 parent::init() 这种非标准方式,那 $id 就永远是 null,且后续任何赋值都会触发 Fatal error: Cannot modify readonly property。
- 子类构造函数参数顺序和父类不一致,传参错位,导致只读属性被设成错误值,且无法修正
- 父类构造函数有副作用(如写日志、发事件),子类跳过它,表面能跑,实际业务状态已偏移
- 使用 traits 注入构造逻辑时,trait 里的初始化代码可能和父类构造函数冲突,
readonly属性被多次赋值,PHP 直接中止
真正难缠的不是语法报错,而是那些“看起来正常运行,但状态已腐化”的情况——比如父类靠 protected 属性缓存计算结果,子类无意中绕过初始化,后续所有基于该缓存的逻辑都返回旧值,这种 bug 往往要追进 Zend 引擎层才能定位。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











