PHP 8.4不对称可见性:带存取器的属性赋值为何未报错?
为什么PHP 8.4中带存取器的
public private(set)属性允许外部赋值? 你遇到的差异是因为PHP 8.4对「带存取器的属性」和「无存取器的属性」处理private(set)修饰符的逻辑完全不同:
1. 无存取器的场景(第二个示例)
public private(set) string $phone;是PHP 8.4专门为无存取器属性设计的语法,直接给属性的读、写操作分别指定可见性:
- 读操作(
$foo->phone)权限为public,外部可以正常读取; - 写操作(
$foo->phone = ...)权限为private,外部直接赋值会触发可见性检查,抛出Cannot access private property PrefixStyle::$phone错误,这符合预期。
2. 带存取器的场景(第一个示例)
当你为属性显式定义get/set存取器时,属性上的private(set)修饰符会被PHP忽略——此时存取器的可见性需要直接在存取器方法前声明。
你的代码里没有给set存取器添加private修饰,所以set存取器默认继承了属性的public可见性。外部执行$foo->phone = ...时,本质是调用了public权限的set存取器,自然不会触发权限错误,赋值就能成功。
正确的写法:让带存取器的属性仅允许内部赋值
如果要让带存取器的属性的写操作限制在类内部,需要把private修饰符直接加在set存取器前面:
class PrefixStyle { public string $phone { get { return $this->phone; } private set { $this->phone = $value; } } }
此时外部执行赋值操作会触发权限错误,和无存取器场景的行为一致。
另外补充:你第一个示例里的set存取器代码$this->phone = $value没有触发无限递归,是因为PHP 8.4的存取器设计了特殊逻辑——在存取器内部直接访问属性本身时,会跳过存取器逻辑,直接操作底层存储,避免递归调用。
内容的提问来源于stack exchange,提问作者Nitram Nekonečný
相关产品推荐
相关产品推荐

