为什么这样的构造会通过引用中断编辑?

时间:2016-01-30 09:08:40

标签: php

在PHP 7中,我使用这种构造来通过引用

处理一些数组值
foreach ($this->values['key'] ?? [] as &$sub_value) {
    $sub_value['sub_key'] = 'new value';
}

我用" ?? []"如果key不存在或为null则不显示错误。 问题是" ?? []"添加PHP不会对目标值进行任何更改,仅在局部变量中(必须是链接,但在这种情况下表现得像我没有指定"&"):

class DefaultSandbox extends PHPUnit_Framework_TestCase
{
    private $values = array (
        'key' =>
            array (
                1 =>
                    array (
                        'external_link' => '',
                        'description' => 'ku1231',
                    ),
                2 =>
                    array (
                        'is_external' => '1',
                        'external_link' => 'http://some.ru',
                        'description' => 'LAME',
                    ),
            ),
    );

    public function testDefault()
    {
        foreach ($this->values['key'] ?? [] as &$sub_value) {
            $sub_value['sub_key'] = 'new value';
        }

        print_r($this->values['key']);
    }

}
  

阵列(       [1] =>排列           (               [external_link] =>               [描述] => ku1231           )

[2] => Array
    (
        [is_external] => 1
        [external_link] => http://some.ru
        [description] => LAME
    )
     

为什么会这样?代码没有" ?? []"工作正常:

        foreach ($this->values['key'] ?? [] as &$sub_value) {
            $sub_value['sub_key'] = 'new value';
        }

        print_r($this->values['key']);
  

阵列(       [1] =>排列           (               [external_link] =>               [描述] => ku1231               [sub_key] =>新的价值           )

[2] => Array
    (
        [is_external] => 1
        [external_link] => http://some.ru
        [description] => LAME
        [sub_key] => new value
    )

2 个答案:

答案 0 :(得分:2)

它将左侧作为表达式的一部分,所以基本上它是一个数组的副本。您仍然可以修改该元素,但只是在该副本中。

如果键值为null,解决方法是在循环之前分配空数组。

答案 1 :(得分:2)

正在发生的事情是由于??的工作方式,而数组是值,而不是对象。

??相当于说:

(isset($arr) ? $arr : [])

或者,更长篇(但并不完全准确,但对于这个例子足够接近):

if(isset($arr) {
    $__temp = $arr;
} else {
    $__temp = [];
}

因为数组是值,所以?:运算符(和扩展名为??)会返回一个新值;不是原始变量。

当您遍历结果时,您将迭代该临时值,而不是原始数组。

在您的情况下,您需要执行以下操作:

if(!isset($arr)) {
     $arr = [];
}

开始循环迭代之前;然后你会得到你期望的结果。

<小时/> 顺便说一下,如果你遍历一个对象,你将得到你想要获得的结果:

$obj = (object)[1, 2, 3];

foreach($obj ?? [] as &$val) {
    $val++;
}

最后,$obj将包含2,3和4.这是因为对象的“值”实际上是对象本身的引用,因此($obj ?? []) return(基本上)是原始对象。