__get 在访问不可见(private/protected)或不存在的属性时触发,不作用于 public 属性;需严格接收字符串参数 $name 并返回值,常用于懒加载、日志、权限控制,须与 __set 配合实现可写,继承中需显式调用父类方法。

__get 方法什么时候会被触发
当访问一个不可见(private/protected)或不存在的属性时,PHP 会自动调用 __get。它不会在 public 属性上触发,也不会在对象有该属性且可访问时触发。
- 常见错误现象:
Notice: Undefined property: MyClass::$name出现,说明__get根本没运行 —— 很可能属性是 public 的,或者拼写错了,又或者你忘了加return导致返回 null 后继续报错 - 使用场景:实现懒加载(比如数据库字段只在首次访问时查)、统一日志记录、对属性访问做权限过滤
- 注意:如果类中定义了
public $name,哪怕同时写了__get,访问$obj->name也绝不会进__get
__get 的参数和返回值必须严格匹配
__get 只接收一个参数:$name,类型是 string;必须有 return,否则返回 null,容易掩盖逻辑问题。
- 参数差异:
$name是属性名字符串,不是变量引用,不能通过它直接读取原始属性值(得用$this->$name或反射) - 性能影响:每次访问都走方法调用,比直接读属性慢;如果里面做了 DB 查询或文件读取,更要警惕重复触发
- 典型写法:
public function __get($name) { if ($name === 'data') { if (!isset($this->cache['data'])) { $this->cache['data'] = $this->loadFromDB(); } return $this->cache['data']; } throw new RuntimeException("Cannot read property '$name'"); }
__get 和 __set 配合使用时的常见陷阱
很多人只写 __get,结果发现赋值失败还报错,是因为 PHP 不会自动帮你处理写操作 —— __set 是独立方法,不写就不会生效。
1、数据调用该功能使界面与程序分离实施变得更加容易,美工无需任何编程基础即可完成数据调用操作。2、交互设计该功能可以方便的为栏目提供个性化性息功能及交互功能,为产品栏目添加产品颜色尺寸等属性或简单的留言和订单功能无需另外开发模块。3、静态生成触发式静态生成。4、友好URL设置网页路径变得更加友好5、多语言设计1)UTF8国际编码; 2)理论上可以承担一个任意多语言的网站版本。6、缓存机制减轻服务器
- 常见错误现象:执行
$obj->name = 'abc'后,var_dump($obj->name)还是 null 或旧值,甚至报Fatal error: Cannot assign to read only property - 兼容性注意:PHP 8.2+ 对只读属性(
readonly)有额外限制,__set无法绕过;而__get在 readonly 类里依然能被调用 - 建议:如果需要支持写,就成对实现;如果只读,明确抛出异常,别留空或静默忽略
__get 在继承和 final 类中的行为差异
子类可以重写 __get,但父类的实现不会自动代理;如果父类方法是 final,子类无法覆盖。
立即学习“PHP免费学习笔记(深入)”;
- 使用场景:基类封装通用属性代理逻辑(如配置项 fallback),子类按需扩展
- 容易踩的坑:子类重写了
__get却忘了调用parent::__get($name),导致父类定义的属性全部失效 - 调试技巧:在
__get开头加echo "Getting $name";,确认是否真被调用;配合debug_backtrace()查看谁触发了它
__get 处理这个属性”——靠字符串匹配容易漏,靠白名单又僵硬;边界情况往往藏在继承链和 visibility 切换里,一不留神就掉进静默失败的坑。










