PHP类:一个方法中的引用变量影响另一个方法中的非引用变量
我对下面例子中的行为感到困惑。我在一个项目中偶然发现了这个问题,花了几个小时才把问题缩小到一个简单的例子。这是我的简单测试类:PHP类:一个方法中的引用变量影响另一个方法中的非引用变量,php,class,properties,scope,reference,Php,Class,Properties,Scope,Reference,我对下面例子中的行为感到困惑。我在一个项目中偶然发现了这个问题,花了几个小时才把问题缩小到一个简单的例子。这是我的简单测试类: <?php class Foo { public $sess = [['name' => 'John']]; public function info() { $this->runTest(); echo $this->sess[0]['name']; } private fun
<?php
class Foo {
public $sess = [['name' => 'John']];
public function info() {
$this->runTest();
echo $this->sess[0]['name'];
}
private function runTest() {
$localSess = &$this->sess[0];
$this->sessTest();
}
private function sessTest() {
$sessCopy = $this->sess;
$this->sess[0]['name'] = 'Bob';
$this->sess = $sessCopy;
}
}
$myFoo = new Foo;
$myFoo->info();
因此我决定创建一个更简单的示例来说明相同的问题:
$a = [['name' => 'John']];
$b = $a; // makes a copy of `$a`
$b[0]['name'] = "Bob";
echo $a[0]['name]; // returns "John" as expected
但是,如果您这样做了:
$a = [['name' => 'John']];
/* var_dump($a) returns:
array(1) {
[0]=>
array(1) {
["name"]=>
string(4) "John"
}
}
*/
$local = &$a[0]; // seems to modify $a[0], so its type &array
/* var_dump($a) returns:
array(1) {
[0]=>
&array(1) {
["name"]=>
string(4) "John"
}
}
*/
$b = $a; // makes a copy of `$a`
$b[0]['name'] = "Bob";
echo $a[0]['name]; // returns "Bob"
我承认这种行为很奇怪,但在多个PHP文档注释中都有记录:
事实证明,这实际上是2000年首次报告的PHP错误:
本应更新文档,但我找不到:
由于PHP内部工作的特殊性,如果引用数组的单个元素,则
数组被复制,无论是通过赋值还是通过数组中的值传递
函数调用时,引用将作为数组的一部分复制。这
意味着对任一数组中任何此类元素的更改都将被删除
在其他数组(和其他引用)中重复,甚至
如果数组具有不同的作用域(例如,一个是参数
一个函数内部,另一个是全局的)!未包含的元素
复制时的引用,以及分配给
数组副本之后的其他元素将起作用
通常(即独立于其他阵列)
但是,由于性能原因,它被标记为“不会修复”。
值得注意的意见:
我们已经讨论过这个问题,为了正确地解决这个问题,它将大大降低php的性能
因此,将记录这种行为
尽管它从未被记录在案
我已经决定提出关于这个问题的另一个bug报告,看看在这个问题上的立场是否已经改变
我现在重新报告了这个问题:
解决
解决办法之一是:
$b = unserialize(serialize($a));
另一个是:
function array_clone($array) {
return array_map(function($element) {
if ((is_array($element))) {
return array_clone($element);
} else if (is_object($element)) {
return clone $element;
} else {
return $element;
}
}, $array);
}
$b = array_clone($a);
呵呵。这似乎只会影响你。现在我真的很好奇。进一步调查发现,引用数组元素会使数组保留引用,因此任何进一步复制数组的尝试都会保留引用。不过请注意,直接复制元素。在这里,在.Odd中发现了一些东西,这是非常保守的IMHO,并记录在文档注释中,哦,天哪……我重新报告了问题:。让我们看看他们怎么说。你的简化例子肯定有助于进一步说明这个问题。但至少那里的一切都在同一个范围内。(不要误解我的意思:这仍然是非常违反直觉的,而且感觉有问题。)但是一旦你的变量在不同的范围内,你就不知道是什么打击了你,使用OOP,你甚至可能不知道调用你的方法的方法中发生了什么。我想这里的教训是:不要引用数组元素,特别是如果那些数组是全局的或全局的(即类中的属性)。@Stoppeye yes Agreed或者您可以使用一种变通方法。不是很好,但是很有用。