我明白为什么
$a = new ArrayObject();
$a['ID'] = 42;
$b = &$a['ID'];
$c = $a;
$c['ID'] = 37;
echo $a['ID']."\n";
echo $b."\n";
echo $c['ID']."\n";
输出37,42,37
,而
$a = new ArrayObject();
$a['ID'] = 42;
$b = &$a['ID'];
$c = $a;
$b = 37;
echo $a['ID']."\n";
echo $b."\n";
echo $c['ID']."\n";
输出37,37,37
在这两种情况下,$b
都是对$a['ID']
的引用,而$c
是指向与$a
相同的对象的指针。
当$b
更改$a['ID']
和$c['ID']
更改时,因为分配$b
会更改$a['ID']
引用的值。
当$c['ID']
更改时,会为$a['ID']
分配新的int,$b
不再引用$a['ID']
。
但这让我感到高兴
$a = new ArrayObject();
$a['ID'] = 42;
$b = &$a['ID'];
$c = $a;
$c['ID'] &= 0;
$c['ID'] |= 37;
echo $a['ID']."\n";
echo $b."\n";
echo $c['ID']."\n";
(输出37,37,37)
这是定义的行为吗? 我在文档中没有看到任何相关内容......
答案 0 :(得分:3)
让我们以此代码为基础:(refcounting documentation)
$a = new ArrayObject();
$a['ID'] = 42;
$b = &$a['ID'];
$c = $a;
xdebug_debug_zval('a');
xdebug_debug_zval('b');
xdebug_debug_zval('c');
这给出了:
a:
(refcount=2, is_ref=0),
object(ArrayObject)[1]
public 'ID' => (refcount=2, is_ref=1),int 42
b:
(refcount=2, is_ref=1),int 42
c:
(refcount=2, is_ref=0),
object(ArrayObject)[1]
public 'ID' => (refcount=2, is_ref=1),int 42
正如你所说:
$a
是一个对象,$b
是$a['ID']
的引用($a['ID']
和$b
:refcount=2, is_ref=1
)
和$ c is copy as a reference (since PHP5),所以$ c是$ a的引用(它现在是同一个对象:refcount=2, is_ref=0
)
如果我们这样做:$c['ID'] = 37;
我们得到:
a:
(refcount=2, is_ref=0),
object(ArrayObject)[1]
public 'ID' => (refcount=1, is_ref=0),int 37
b:
(refcount=1, is_ref=0),int 42
c:
(refcount=2, is_ref=0),
object(ArrayObject)[1]
public 'ID' => (refcount=1, is_ref=0),int 37
$c['ID']
被分配了一个新的int
so =>
$b
变得独立(refcount=1
和is_ref=0
),以及$a['ID']
和$c['ID']
但由于$c
和$a
是相关的,$a['ID']
和$c['ID']
采用相同的值37。
现在,我们来看看基本代码:$c['ID'] &= 0;
<强>更新强>: 出乎意料的是,我们得到了:
a:
(refcount=2, is_ref=0),
object(ArrayObject)[1]
public 'ID' => (refcount=2, is_ref=1),int 0
b:
(refcount=2, is_ref=1),int 0
c:
(refcount=2, is_ref=0),
object(ArrayObject)[1]
public 'ID' => (refcount=2, is_ref=1),int 0
而不是:(if:$c['ID'] = $c['ID'] & 0;
)
a:
(refcount=2, is_ref=0),
object(ArrayObject)[1]
public 'ID' => (refcount=1, is_ref=0),int 0
b:
(refcount=1, is_ref=0),int 42
c:
(refcount=2, is_ref=0),
object(ArrayObject)[1]
public 'ID' => (refcount=1, is_ref=0),int 0
ArrayObject实现ArrayAccess所以:
如评论中所述和documented here:
直接修改是完全替换数组维度的值,如$ obj [6] = 7.另一方面,间接修改只会更改维度的一部分,或尝试通过引用另一个变量来指定维度,如$ obj [6] [7] = 7或$ var =&amp; $ OBJ [6]。使用++的增量和使用 - 的减量也以需要间接修改的方式实现。
可能的答案:
“组合运算符(+ =, - =,&amp; =,| =)可以以相同的方式工作(间接修改。)”:
refcount
和is_ref
因此(在我们的例子中)不会影响所有人的价值 相关变量被修改。 ($c['ID']
=&gt;$a['ID']
=&gt;$b)
答案 1 :(得分:2)
它或多或少地定义了(但有时没有记录)行为;主要是因为$a
不是array
而是ArrayObject
。
让我们先来看看你的第三个代码片段:
$a = new ArrayObject();
$a['ID'] = 42;
$b = &$a['ID'];
$c = $a;
$c['ID'] &= 0;
最后一项任务转换为:
$tmp = &$c->offsetGet('ID');
$tmp &= 0; // or: $tmp = $tmp & 0;
这里的外卖点是仅调用 offsetGet()
,它会将引用返回到$c['ID']
,如{{3}所述}}。由于未调用offsetSet()
,因此$b
的值也会发生变化。
顺便说一句,增量(++)和减量运算符( - )以类似的方式工作,不会调用offsetSet()
。
<强>差异强>
这与你的第一个例子不同:
$a = new ArrayObject();
$a['ID'] = 42;
$b = &$a['ID'];
$c = $a;
$c['ID'] = 37;
最后一个语句具有以下等价物:
$c->offsetSet('ID', 37);
在将新值分配给$c['ID']
之前,之前的值实际为unset()
;这就是为什么$b
是唯一仍然保留42
的变量。
当您使用对象而不是数字时,可以看到此行为的证据:
class MyLoggerObj
{
public function __destruct()
{
echo "Destruct of " . __CLASS__ . "\n";
}
}
$a = new ArrayObject();
$a['ID'] = new MyLoggerObj();
$a['ID'] = 37;
echo $a['ID']."\n";
Destruct of MyLoggerObj
37
如您所见,析构函数在MyLoggerObj
上调用;那是因为在这种情况下,没有任何变量可以保留该值。
<强>加成强>
如果您试图通过延长offsetGet()
来查找何时调用offsetSet()
和ArrayObject
,那么您会发现自己无法正确模仿mixed &offsetGet($key);
而感到失望。实际上,这样做会改变ArrayObject
的行为,从而无法证明这个类的行为。