3

我在 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。

4

2 回答 2

3

您的问题是对 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按引用表示法(air4x 的帽子提示)来避免额外的分配。请注意,如果您正在使用对象数组,它们已经通过引用传递。

foreach($top_level_array as &$current_top_level_member)

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

PHP 使用惰性复制机制(也称为写时复制),该机制在修改变量之前不会实际创建变量的副本。

来源:http ://www.thedeveloperday.com/php-lazy-copy/

于 2012-10-07T03:03:57.767 回答
1

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

foreach ($top_level_array as &$current_top_level_member) {
于 2012-10-07T09:46:50.067 回答