未声明属性"example"可调用?代码运行及echo输出次数疑问
问题解答
咱们逐个拆解你的疑问:
1. 能否在未声明的情况下调用名为"example"的属性?
完全可以!在PHP中,当你尝试给类中未定义的属性(或是当前上下文无权限直接访问的私有/受保护属性)赋值时,PHP会自动触发__set()魔术方法来处理这个操作——这也是你的代码能正常运行的核心原因。
2. 这段代码为什么能正常运行?
你的代码核心就是利用了PHP的__set()魔术机制:
- 当执行
$obj->example = "<strong>hello</strong>";时,因为SetMissing类里并没有预先定义$example属性,PHP会自动调用__set()方法。 - 在
__set()方法里,你做了两件关键事:打印_SET,然后通过$this->$name = ...把过滤后的值赋值给了这个动态创建的属性。注意:这一步执行完后,$obj对象里就实实在在存在$example属性了! - 后续再访问
$obj->example时,因为属性已经存在,就直接返回对应的值,不会再触发魔术方法。
完整的代码执行流程可以拆解为:
class SetMissing { public function __set($name, $value) { echo "_SET"; // 动态创建属性并赋值 $this->$name = filter_var($value, FILTER_SANITIZE_STRING); } } $obj = new SetMissing(); // 第一次赋值:example不存在,触发__set(),打印_SET,同时创建example属性并赋值为过滤后的"hello" $obj->example = "<strong>hello</strong>"; // 直接读取已存在的example属性,输出"hello"加换行 echo $obj->example . PHP_EOL ; // 第二次赋值:example已存在,直接覆盖值,不会触发__set() $obj->example = "<strong>hello</strong>"; // 读取已存在的属性,输出"hello" echo $obj->example;
3. 为什么_SET仅打印一次而不是两次?
原因很直白:
- 第一次给
example赋值时,属性不存在,触发__set(),所以打印了_SET,同时动态创建了example属性。 - 第二次赋值时,
example已经是$obj对象的一个实际属性了,PHP会直接对这个已有属性做赋值操作,不会再触发__set()魔术方法,自然也就不会再打印_SET。
如果想要每次赋值都触发__set(),可以把属性的存储逻辑改成私有数组(避免直接创建公共属性),比如:
class SetMissing { private $properties = []; public function __set($name, $value) { echo "_SET"; $this->properties[$name] = filter_var($value, FILTER_SANITIZE_STRING); } public function __get($name) { return $this->properties[$name] ?? null; } }
这样每次外部赋值都会触发__set(),_SET就会打印两次了。
内容的提问来源于stack exchange,提问作者user9718914
相关产品推荐
相关产品推荐

