Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/280.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
PHP类:一个方法中的引用变量影响另一个方法中的非引用变量_Php_Class_Properties_Scope_Reference - Fatal编程技术网

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或者您可以使用一种变通方法。不是很好,但是很有用。