基本上我理解参考工作是
$a = 5;
$b = &$a;
$a = 10;
echo $b; // 10;
然而,在这段代码中,我出乎意料(对我来说,可能有一个解释)结果
class Room {
private $users = array();
public function addUser(&$user){
$this->users[] = $user;
}
}
$users = array(
1 => 'Tom',
2 => 'Hank',
3 => 'Sam',
4 => 'John'
);
$room = new Room();
$room->addUser($users[1]);
$room->addUser($users[3]);
unset($users[3]);
echo "<pre>" . print_r($room, true) . "</pre>";
echo "<pre>" . print_r($users, true) . "</pre>";
我希望在取消设置$users[3]
之后,$room
内的唯一用户为Tom
,但情况并非如此,Tom
和{{1}存在于对象中。为什么Sam
不会影响对象的属性?
即使我在示例中更进一步并创建了一个类unset
,效果仍然相同
User
答案 0 :(得分:4)
Unset对符号而非参考目标进行操作。
这就是为什么在未定义的变量上使用unset不会引发任何类型的错误。
$a = 10;
$b = &$a;
unset($b); // forget the name "$b" exists.
echo $a; // 10
如果要在两个地方取消设置,则必须将null
分配给其中一个变量。这是一个“难以设置”,而不是你现在正在做的“软设置”。
您也没有指定参考,而是指定副本。
$this->users[] = &$user;
答案 1 :(得分:1)
PHP变量存储在名为&#34; zval&#34;的容器中。一个zval 容器除了包含变量的类型和值之外,还包含两个 额外的信息。第一个被称为&#34; is_ref&#34;而且是一个 boolean值,指示变量是否是a的一部分 &#34;参考集&#34;。 (...)因为PHP允许用户土地引用,如 由&amp;创建操作员,zval容器也有内部 引用计数机制来优化内存使用。这第二个 一条名为&#34; refcount&#34;的附加信息包含多少信息 变量名(也称为符号)指向这个zval容器。
(...)
&#34; refcount&#34;达到零。 &#34;引用&#34;当任何符号链接到时,会减少一个 变量容器离开范围(例如,当函数结束时)或 在符号上调用unset()时。
数组示例:
<?php
$a = array(
0 => 'aaa',
1 => 'bbb',
2 => 'ccc',
);
debug_zval_dump($a);
// ... string(3) "bbb" refcount(1) ...
$b = array();
$b[0] = &$a[0];
$b[1] = &$a[1];
$a[1] = 'ddd';
debug_zval_dump($a);
// ... &string(3) "bbb" refcount(2) ...
debug_zval_dump($b);
// ... &string(3) "bbb" refcount(2) ...
unset($a[1]);
debug_zval_dump($a);
/*
array(2) refcount(2){
[0]=>
&string(3) "aaa" refcount(2)
[1]=>
&string(3) "ddd" refcount(2)
}
*/
debug_zval_dump($b);
// ... string(3) "ddd" refcount(1) ...
var_dump($a);
/*
array (size=2)
0 => &string 'aaa' (length=3)
2 => string 'ccc' (length=3)
*/
var_dump($b);
/*
array (size=2)
0 => &string 'aaa' (length=3)
1 => string 'ddd' (length=3)
*/
答案 2 :(得分:0)
我认为你想要的效果与你尝试的方式之间存在轻微的逻辑问题。
如果我理解正确,您希望将用户分配到容器,然后以一种在容器中也未设置的方式取消设置其中一个用户。此
unset($users[3]);
取消设置用户数组的第四个元素的值。
如果我们$user[3] = 'foo';
,相应容器条目中包含的值也将设置为'foo'
,但容器的索引键本身不会被取消设置,或受参考影响,因为它不是参考值的一部分
如果要取消设置用户,要么跟踪分配给容器中哪个用户的索引键,然后删除具有此索引键的用户,要么将$users[3]
的值设置为{{ 1}}(或任何适合您的需求)并在处理容器时跳过null
值
答案 3 :(得分:0)
您可以更改数组的值,如下所示:
代码:
private $users = array();
public function addUser(&$user){
$this->users[] = &$user;
}
}
$users = array(
1 => 'Tom',
2 => 'Hank',
3 => 'Sam',
4 => 'John'
);
$room = new Room();
$room->addUser($users[1]);
$room->addUser($users[3]);
$users[3] = "AAA123";
echo "<pre>" . print_r($room, true) . "</pre>";
echo "<pre>" . print_r($users, true) . "</pre>";
输出:
Room Object
(
[users:Room:private] => Array
(
[0] => Tom
[1] => AAA123
)
)
Array
(
[1] => Tom
[2] => Hank
[3] => AAA123
[4] => John
)
但是以这种方式删除是不可能的...我不知道该怎么解释,所以举个例子:
$a = 10;
$b = &$a;
unset($a);
echo $b; // 10
然后删除变量名,直到refcount
达到0为止,才删除zval(container)...然后“垃圾回收”将全部工作并删除zval ...
因此,仅在这种情况下,方法unset()才删除变量名称...
答案 4 :(得分:-1)
小心。
您正在向addUser()
传递对构建数组'Tom'
时分配的字符串$users
的引用。
首先,addUser()
应该是$this->users[] =& $user;
,否则您将把值复制到$this->users[]
而不是共享参考。
现在,$users
和Room::$users
共享相同的对象,但unset($users[3])
会删除索引3
映射的元素从数组,它不会破坏映射对象。