我在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 回答
您的问题是对PHP如何在foreach结构中提供“ Value ”的误解 .
变量$ current_top_level_member是数组中值的副本,而不是对$ top_level_array内部的引用 . 因此,所有工作都在副本上进行,并在循环完成后丢弃 . (实际上它位于$ current_top_level_member变量中,但$ top_level_array永远不会看到更改 . )
你想要一个参考:
EDIT:
您也可以通过引用符号(帽子提示到air4x)使用
foreach
以避免额外的分配 . 请注意,如果您正在使用对象数组,则它们已通过引用传递 .为了回答你关于为什么PHP默认使用副本而不是引用的问题,这仅仅是因为语言的规则 . 标量值和数组按值分配,除非使用
&
前缀,并且始终通过引用(as of PHP 5)分配对象 . 这可能是由于普遍的共识,通常更好地处理所有期望对象的副本 . 但是 - 它并不像你想象的那么慢 . PHP使用一个名为copy on write的惰性副本,它实际上是一个只读引用 . 在第一次写入时,复制完成 .您可以在
$current_top_level_member
之前添加&
,并将其用作原始数组中变量的引用 . 然后你将对原始数组进行更改 .