我有一个问题已经破坏了我想要做事的方式很长时间了。它与在 PHP 中使用 magic get 和 set 以及尝试对对象进行预增量有关。我有一个如下所示的 PHP 类:
class Foo {
public $object;
function __construct() {
$this->object = array("bar" => 1);
}
function & __get($name) {
return $this->object[$name];
}
function __set($name, $value) {
echo "Old value: ". $this->object[$name] ." - New value: ". $value ."\n";
$this->object[$name] = $value;
}
}
注意__get
方法中的&
。现在我运行这段代码:
$o = new Foo();
echo "First test\n";
$o->bar = 2;
echo "Second test\n";
$o->bar = $o->bar + 1;
echo "Third test\n";
$o->bar += 1;
echo "Fourth test\n";
++$o->bar;
输出是:
First test
Old value: 1 - New value: 2
Second test
Old value: 2 - New value: 3
Third test
Old value: 4 - New value: 4
Fourth test
Old value: 5 - New value: 5
第三个和第四个测试有一个意想不到的(我)行为。看起来 $this->object['bar'] 返回要设置的值,而不是我预期的旧值。为什么这个值在实际设置之前就已经设置好了?
如果我从 __get
方法中删除 &
,这将起作用,所以我猜它与 PHP 所做的引用管理有关。但我希望第三个测试的行为方式与第二个相同,但事实并非如此。
我真的不明白。任何帮助将不胜感激。
最佳答案
结果实际上(经过仔细考虑)是我所期望的。
第一次测试
代码:$o->bar = 2;
输出:旧值:1 - 新值:2
操作,按顺序:
- 为
$bar
赋一个新值(调用__set()
)
显然,这只是放弃旧值并在其位置放置一个新值。没什么复杂的。
第二次测试
代码:$o->bar = $o->bar + 1;
输出:旧值:2 - 新值:3
操作,按顺序:
- 获取
$bar
的副本(调用__get()
) - 加一个
- 为
$bar
赋一个新值(调用__set()
)
计算表达式的右侧,并将结果分配给左侧。实例变量 $bar
的值在右侧的评估期间未被修改,因此您在 __set()
调用开始时看到它的旧值。
第三次测试
代码:$o->bar += 1;
输出:旧值:4 - 新值:4
操作,按顺序:
- 获取对
$bar
的引用(调用__get()
) - 加一个
- 为
$bar
赋一个新值(调用__set()
)
这很有趣 - 乍一看,我有点惊讶您看到 __set()
使用此操作生成的输出。因为您正在增加原始 zval 中保存的值,而不是分配一个全新的值 - 因此是一个全新的 zval - 就像前两个一样,看来 __set()
调用是多余的。
但是,当 __set()
被调用时,您看到的输出正是您所期望的,因为引用的值 在之前已经递增了em> __set()
被调用了。传递给 __set()
的值是自增操作的结果,所以它不会导致另一个被添加到它,它只是分配 $foo->bar< 的值
到 $foo->bar
- 所以您会看到旧值和新值相同。
第四次测试
代码:++$o->bar;
输出:旧值:5 - 新值:5
...在语义上与第三个测试相同。以完全相同的顺序进行完全相同的操作会产生完全相同的输出。同样,有点奇怪的是根本没有任何输出,但是你去吧。
我发明的第五个测试
代码:$o->bar++;
输出:旧值:5 - 新值:6
...在语义上与第二个测试相同。这又很有趣,也有点出乎意料,但它也是有道理的,因为 $i++
返回了 $i
的旧值。
猜测 __set()
在第三次和第四次测试中被不必要地调用的原因是:
- (不太可能但可能)因为计算
__get()
返回的是引用还是副本比简单调用__set()
的计算成本更高> - 这似乎不太可能,因为函数调用通常非常昂贵。 - (更有可能)因为
__set()
函数可以包含与实际赋值操作无关的代码,如果该代码在值被赋值时不运行,可能会带来严重的不便被改变了。例如,如果要实现某种事件驱动架构,当某些值发生变化时会触发事件,如果它只适用于直接赋值,那将很烦人。
关于php - 在 PHP 中预增量并定义魔法 get 和 set,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10520021/