首页 文章

为什么多维子数组的排序顺序会在foreach循环用于排序结束后立即恢复?

提问于
浏览
2

我在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()函数都没有在相关项目的单独实例上运行(而是在引用上,即在适当位置),但上面的结果似乎表明不是这样?如果是这样,我将如何能够执行所需的排序操作?

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

PS . 没关系在这个例子中要排序的奇怪数组的设计背后的原因,它当然只是在更复杂的代码中真正问题的简化PoC .

2 回答

  • 1

    您的问题是对PHP如何在foreach结构中提供“ Value ”的误解 .

    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];
    

    EDIT:

    您也可以通过引用符号(帽子提示到air4x)使用 foreach 以避免额外的分配 . 请注意,如果您正在使用对象数组,则它们已通过引用传递 .

    foreach($top_level_array as &$current_top_level_member)
    

    为了回答你关于为什么PHP默认使用副本而不是引用的问题,这仅仅是因为语言的规则 . 标量值和数组按值分配,除非使用 & 前缀,并且始终通过引用(as of PHP 5)分配对象 . 这可能是由于普遍的共识,通常更好地处理所有期望对象的副本 . 但是 - 它并不像你想象的那么慢 . PHP使用一个名为copy on write的惰性副本,它实际上是一个只读引用 . 在第一次写入时,复制完成 .

    PHP使用一种惰性复制机制(也称为写时复制),在修改变量之前,它实际上并不创建变量的副本 . 资料来源:http://www.thedeveloperday.com/php-lazy-copy/

  • 2

    您可以在 $current_top_level_member 之前添加 & ,并将其用作原始数组中变量的引用 . 然后你将对原始数组进行更改 .

    foreach ($top_level_array as &$current_top_level_member) {
    

相关问题