
PHP私有属性只能在定义它的类内部访问
私有属性不是“藏起来就安全”,而是语言强制的访问边界。你写 $this->name 没问题,但子类里直接读 $obj->name 或 $child->name 会报 Fatal error: Cannot access private property。
常见错误现象:继承后想复用父类字段,却在子类方法里直接写 $this->id —— 如果 $id 是 private,哪怕它在父类中定义,子类也看不到。
- 要用
protected替代private,如果子类确实需要访问该属性 - 若坚持封装,把读写逻辑收进父类的
public或protected方法里(比如getId()、setName()) - PHP 不支持“包级私有”或“模块私有”,只有
private/protected/public三级
构造函数里赋值私有属性是唯一可靠初始化方式
别指望在类体里写 private $count = 0; 就万事大吉——这行得通,但一旦要依赖外部输入、配置或运行时计算,就必须靠 __construct()。
使用场景:连接数据库时私有属性存 $pdo 实例,或缓存对象存 $cacheDriver,这些没法静态初始化。
立即学习“PHP免费学习笔记(深入)”;
- 避免在方法里首次调用时才初始化私有属性(比如
if (!isset($this->logger)) { $this->logger = new Logger(); }),容易漏判、状态不一致 - 构造函数参数应明确对应私有属性用途,别塞一堆
array $options然后在内部拆解——可读性和类型提示全丢 - PHP 8.1+ 支持属性提升(promoted properties),可把
private Logger $logger直接写进构造函数签名,等价于手动赋值
var_dump() 和 debug_print_backtrace() 看不到 private 属性值?不是 bug 是设计
var_dump() 显示私有属性时会带类名前缀,像 object(User)#1 (2) { ["name":"User":private]=> string(4) "Tom" }。这不是隐藏,是标识作用域;但如果你用 json_encode($obj),私有属性默认被忽略——因为 JsonSerializable 接口没实现的话,序列化只走 public 字段。
性能影响:私有属性本身不拖慢运行,但过度依赖魔术方法(如 __get())拦截私有属性访问,会明显增加开销。
- 调试时想看全量状态,用
get_object_vars($obj)只返回public属性;要完整结构,改用反射:(new ReflectionObject($obj))->getProperties(ReflectionProperty::IS_PRIVATE) - 不要为了“让 var_dump 更好看”而重写
__debugInfo()并暴露敏感字段(比如数据库密码) - 测试中 mock 私有属性?别试。要么改
private为protected,要么通过行为验证(比如调用公开方法后检查输出)
PHP 8.2 的 readonly class 对私有属性的影响
加了 readonly 的类,所有属性(包括 private)都只能在构造函数里赋值一次。这时候私有 + 只读,才是真正意义上的“不可篡改内部状态”。
容易踩的坑:你以为 private readonly string $token; 很安全,但如果构造时传入的是引用或可变对象(比如 DateTime 实例),后续仍可能被外部修改——readonly 只锁引用,不锁内容。
- 基本类型(
string、int、bool)用readonly private是最稳妥的组合 - 数组和对象需额外防御:构造时用
clone或json_decode(json_encode(...), true)做深拷贝(视情况) - 别在
readonly类里留空私有属性(如private readonly ?Connection $conn;),否则实例化后永远为null,无法补救











