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

Php 为什么用于排序的foreach循环一结束,多维子数组的排序顺序就会恢复?,php,arrays,multidimensional-array,sorting,Php,Arrays,Multidimensional Array,Sorting,我在PHP中遇到了一个非常奇怪的数组排序相关问题,这让我发疯。我已经在谷歌上搜索了几个小时,但仍然没有任何迹象表明其他人有这个问题,或者这应该发生在一开始,所以解决这个谜团将不胜感激 用尽可能少的话描述这个问题:当使用foreach循环根据多层深度嵌套数组中的值对数组进行排序时,结果数组排序顺序会在执行离开循环时立即恢复,即使它在循环中工作正常。为什么会这样,我该如何应对 下面是我的问题的示例代码,希望比上面的句子更清楚一些: $top_level_array = array('key_1' =

我在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);
如您所见,在循环内的排序操作(如预期)之前,排序顺序是“错误的”(即未按最内层数组中的所需值排序),然后在循环内的排序操作(如预期)之后,排序顺序变为“正确的”

到目前为止还不错

但是,一旦我们再次跳出循环,顺序突然恢复到其原始状态,好像排序循环根本没有执行

这是怎么发生的,我怎样才能按照期望的方式对数组进行排序呢

我的印象是,foreach循环和uasort()函数都不对所讨论的项的单独实例进行操作(而是对引用进行操作,即就地操作),但上面的结果似乎表明不是这样?如果是这样,我将如何执行所需的排序操作

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

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

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

foreach($top_level_array as $current_top_level_member)
变量$current_top_level_成员是数组中值的副本,而不是$top_level_数组中的引用。因此,所有工作都发生在副本上,并在循环完成后被丢弃。(实际上它位于$current\u top\u level\u成员变量中,但$top\u level\u数组从未看到更改。)

您需要一个参考:

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使用一个名为“写时复制”的惰性副本,它实际上是一个只读引用。在第一次书写时,将复制

PHP使用一种惰性复制机制(也称为写时复制),它可以 在修改变量之前,不实际创建变量的副本

资料来源:


您可以将
&
添加到
$current\u top\u level\u member
之前,并将其用作原始数组中变量的引用。然后您将对原始数组进行更改

foreach ($top_level_array as &$current_top_level_member) {

就是这样,非常感谢你澄清这件事!但他们究竟为什么要使用副本作为默认行为,它既慢又不直观(IMHO)?!那么该命令不应该被称为“forcopyofech”吗?:)无论如何,我现在在这里收到了两个答案,其中您的答案最为详细,但另一个答案的代码更为优雅,我选择哪一个作为答案?在这种情况下,StackOverflow有什么规则或建议吗?@QuestionOverflow我知道
foreach
的引用语法,但我忽略了在解释之后将其作为一种简写符号。我刚刚把它加在air4x上。此外,我还添加了一些关于该语言为什么会执行默认操作的信息。我希望这有帮助@问题溢出同样,当你有多个正确答案时,最好对这些答案进行投票,然后通过打分来奖励最佳答案(在你看来,并非所有人都会同意)。顺便说一句,欢迎来到StackOverflow!谢谢你提供的额外信息,现在你的答案肯定是最完整的,所以我把它标记为这个问题的答案。可悲的是,我显然没有足够的声誉,不能被允许对事情进行“升级”,但我会尽量记住,等我升级时再这么做。最后,谢谢你的欢迎!:)谢谢开始可能是一个挑战,但你几乎做到了。你只需要再多两个代表就可以投票了:)非常感谢这个优雅的解决方案!但他们究竟为什么要使用副本作为默认行为,它既慢又不直观(IMHO)?!那么该命令不应该被称为“forcopyofech”吗?:)无论如何,我现在在这里收到了两个答案,其中您的答案是最优雅的解决方案代码,但另一个答案更详细,我选择哪一个作为答案?在这种情况下,StackOverflow是否有任何规则或建议?制作副本可以让您在
foreach
中使用它,而无需担心更改原始数组。如果两个答案相似或最有用,请选择第一个答案。对你认为有用的其他答案进行投票。谢谢,一旦我获得足够的声誉,我将立即对你的答案进行投票!
foreach ($top_level_array as &$current_top_level_member) {