php中public属性应避免直接使用,因其破坏封装性,导致数据被随意篡改、校验逻辑失效、行为不一致;推荐用private/protected配合getter/setter控制访问与校验。

public 属性在 PHP 封装中基本不该直接用
直接把属性声明为 public 会破坏封装的核心目标:数据不可随意篡改。哪怕只是临时调试,也容易留下隐患。
常见错误现象:Cannot access private property 这类报错往往不是因为用了 private,而是开发者误以为“设成 public 就省事”,结果后续加校验逻辑时发现属性已被外部代码乱赋值,根本没法统一拦截。
- 构造函数里初始化的配置项(如
$this->baseUrl)若设为public,外部可随时覆盖,导致行为不一致 - 数值型属性(如
$balance)一旦public,就无法阻止负数或非数字写入 - PHP 7.4+ 支持属性类型声明,但类型只在校验赋值时起作用——前提是属性不是
public,否则绕过 setter 就失效
protected 和 private 的边界在哪?看继承是否需要复用逻辑
protected 不是“半私有”,而是明确表达“这个东西子类可能要参与控制”。选错会导致子类要么重复造轮子,要么被迫绕过封装强行访问。
使用场景判断:
- 子类需重写验证逻辑(如不同用户类型对
$status的合法值不同)→ 用protected配合模板方法,或把校验逻辑抽到protected function validateStatus() - 纯内部状态,比如缓存计算结果的
$cachedFullName、连接句柄$pdo→ 必须private,子类不该也不需要碰 - 父类定义了
protected $config,子类直接$this->config['timeout'] = 30→ 这属于破坏封装,应提供setTimeout(int $ms)方法
getter/setter 不是仪式感,而是控制点
没有业务逻辑的 getter/setter 是冗余代码;但缺少它们,就等于放弃对属性生命周期的干预能力。
关键差异:
-
getAge()可以返回格式化字符串("{$this->age} 岁"),而直接读$user->age永远只能拿到原始 int -
setName(string $name)能 trim、转大小写、甚至触发事件($this->eventDispatcher->dispatch(new NameChanged($this))) - PHP 8.1+ 的
readonly属性虽能防写,但无法做输入校验或副作用处理,仍需搭配 setter 使用
容易被忽略的细节:方法可见性必须 >= 属性可见性
子类覆盖父类方法时,不能把 public function setPrice() 改成 protected function setPrice(),否则会报致命错误:Access level to ... must be public。
这意味着:
- 如果属性是
private,配套的 setter/getter 通常得是public(供外部调用)或protected(仅子类调用) - 如果属性是
protected,且你希望子类也能直接读写(不走方法),那 setter/getter 就没必要存在——但这种情况极少,多数时候说明设计已偏离封装意图 - 抽象类中定义
abstract protected function calculateTax(): float,子类实现时必须保持protected或更宽松,不能降级
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











