PHP如何阻止在类外部为实例创建新的成员变量?
阻止PHP类实例被动态添加属性的方法
问题回顾
正如你所说,PHP中类的私有成员无法从外部访问,但默认情况下允许给实例动态添加新属性,比如这段代码:
class Resource { private $test; public function __construct() { echo "in init"; $test = "new val"; // 这里提个小细节:你原来的代码里这是局部变量,不是给类的$test属性赋值,正确写法应该是$this->test } } $r = new Resource(); $r->val = "value"; // 默认允许这种动态添加属性的操作
要阻止这种行为,有两种实用方案:
方案1:重写__set()魔术方法(兼容所有PHP版本)
PHP的__set()魔术方法会在尝试给未定义的属性赋值时自动触发。我们可以在这个方法里抛出错误,直接阻止动态属性的添加:
class Resource { private $test; public function __construct() { echo "in init"; $this->test = "new val"; // 修正为类属性赋值 } public function __set($propertyName, $value) { // 抛出致命错误,明确禁止添加未定义属性 throw new \Error("不允许为Resource类实例添加动态属性:$propertyName"); // 也可以用触发警告的方式,不过致命错误更能强制阻止操作: // trigger_error("禁止添加动态属性 Resource::$propertyName", E_USER_ERROR); } } $r = new Resource(); $r->val = "value"; // 执行这行时会抛出错误,无法完成赋值
方案2:使用readonly类(PHP 8.2+)
如果你使用的是PHP 8.2或更高版本,给类加上readonly关键字是更简洁的方案。readonly类会自动禁止动态添加属性,同时所有类属性默认变为只读(不可修改):
readonly class Resource { private $test; public function __construct() { echo "in init"; $this->test = "new val"; } } $r = new Resource(); $r->val = "value"; // 执行时会抛出Error: Cannot create dynamic property Resource::$val
注意:readonly类有几个限制:不能包含非只读属性,不能定义__set()魔术方法,也不能被其他类继承。如果你的类符合这些限制,这是最优雅的解决方案。
内容的提问来源于stack exchange,提问作者Aanand Natarajan
相关产品推荐
相关产品推荐

