php - 为什么用于排序的foreach循环一结束,多维子数组的排序顺序就会恢复?

标签 php arrays multidimensional-array sorting

我在 PHP 中遇到一个非常奇怪的数组排序相关问题,这让我完全抓狂。我已经在谷歌上搜索了几个小时,但仍然没有任何迹象表明其他人也有这个问题,或者这应该恰好开始,所以非常感谢解决这个谜团的方法!

用尽可能少的词来描述问题:当基于多层嵌套数组中的值对数组进行排序时,使用 foreach 循环,一旦执行离开循环,生成的数组排序顺序就会恢复,即使它在循环内工作正常。为什么会这样,我该如何解决?

这是我的问题的示例代码,希望它比上面的句子更清楚一点:

$top_level_array = array('key_1' => array('sub_array' => array('sub_sub_array_1' => array(1),
                                                               'sub_sub_array_2' => array(3),
                                                               'sub_sub_array_3' => array(2)
                                                              )
                                         )
                        );

function mycmp($arr_1, $arr_2)
{
    if ($arr_1[0] == $arr_2[0])
    {
        return 0;
    }
    return ($arr_1[0] < $arr_2[0]) ? -1 : 1;
}

foreach($top_level_array as $current_top_level_member)
{
    //This loop will only have one iteration, but never mind that...
    print("Inside loop before sort operation:\n\n");
    print_r($current_top_level_member['sub_array']);

    uasort($current_top_level_member['sub_array'], 'mycmp');

    print("\nInside loop after sort operation:\n\n");
    print_r($current_top_level_member['sub_array']);
}
print("\nOutside of loop (i.e. after all sort operations finished):\n\n");
print_r($top_level_array);

输出结果如下:

Inside loop before sort operation:

Array
(
    [sub_sub_array_1] => Array
        (
            [0] => 1
        )

    [sub_sub_array_2] => Array
        (
            [0] => 3
        )

    [sub_sub_array_3] => Array
        (
            [0] => 2
        )

)

Inside loop after sort operation:

Array
(
    [sub_sub_array_1] => Array
        (
            [0] => 1
        )

    [sub_sub_array_3] => Array
        (
            [0] => 2
        )

    [sub_sub_array_2] => Array
        (
            [0] => 3
        )

)

Outside of loop (i.e. after all sort operations finished):

Array
(
    [key_1] => Array
        (
            [sub_array] => Array
                (
                    [sub_sub_array_1] => Array
                        (
                            [0] => 1
                        )

                    [sub_sub_array_2] => Array
                        (
                            [0] => 3
                        )

                    [sub_sub_array_3] => Array
                        (
                            [0] => 2
                        )

                )

        )

)

如您所见,排序顺序在循环内的排序操作之前是“错误的”(即未按最内层数组中的所需值排序)(如预期的那样),然后在排序操作之后变为“正确”在循环内(如预期的那样)。

到目前为止一切顺利。

但是然后,当我们再次进入循环之外时,突然间顺序又恢复到原来的状态,就好像排序循环根本没有执行一样?!?

这是怎么发生的,然后我将如何以所需的方式对这个数组进行排序?

我的印象是,无论是 foreach 循环还是 uasort() 函数都不会在相关项目的单独实例上运行(而是在引用上运行,即就地运行),但上面的结果似乎表明并非如此?如果是这样,我将如何执行所需的排序操作?

(为什么整个互联网上除了我之外没有其他人似乎有这个问题?)

附言。 不要在意这个例子中要排序的奇怪数组设计背后的原因,它当然只是更复杂代码中实际问题的简化 PoC。

最佳答案

您的问题是误解了 PHP 如何在 foreach 构造中提供您的“值”。

foreach($top_level_array as $current_top_level_member)

变量 $current_top_level_member 是数组中值的副本,而不是对 $top_level_array 内部的引用。因此,您所有的工作都发生在副本上,并在循环完成后被丢弃。 (实际上它在 $current_top_level_member 变量中,但是 $top_level_array 永远看不到变化。)

你想要一个引用:

foreach($top_level_array as $key => $value)
{
    $current_top_level_member =& $top_level_array[$key];

编辑:

您还可以使用 foreach by reference notation(提示 air4x)来避免额外的赋值。请注意,如果您使用的是对象数组,则它们已通过引用传递。

foreach($top_level_array as &$current_top_level_member)

要回答您关于为什么 PHP 默认使用副本而不是引用的问题,这仅仅是因为语言规则。标量值和数组按值分配,除非使用 & 前缀,并且对象始终按引用分配 (as of PHP 5)。这可能是由于普遍认为使用对象以外的所有对象的副本通常会更好。但是——它并不像您预期​​的那样慢。 PHP 使用称为写时复制的惰性复制,它实际上是一个只读引用。在第一次写入时,创建副本。

PHP uses a lazy-copy mechanism (also called copy-on-write) that does not actually create a copy of a variable until it is modified.

Source: http://www.thedeveloperday.com/php-lazy-copy/

关于php - 为什么用于排序的foreach循环一结束,多维子数组的排序顺序就会恢复?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12765714/

相关文章:

javascript - 将多维数组连接成一维数组

python - 将多维数组传递给Python中的函数

c - 将来自 strtok() 的 token 存储在双指针 "2d array"中

PHP 和 Javascript 兼容的加密函数

c# - NullReferenceException即使在“new MyType []”之后?

python - 如何在 Python 中对数据数组执行我的函数?

php - 受限笛卡尔积计算 - PHP

php - PSR-2。什么时候大写目录?

PHP - 使用静态方法动态扩展父类

php - 特定类别的用户帖子计数 [Wordpress]