【问题标题】:PHP foreach weirdness with multi-dim array sent over AJAX通过 AJAX 发送多维数组的 PHP foreach 怪异
【发布时间】:2018-06-18 15:35:50
【问题描述】:

我猜这是一个我从未遇到过的已知问题。我有一个多维数组通过 AJAX 发送到 PHP,如下所示:

let pd = {
    vids: $.map(yt_vids_preview.find('tr:has(td :checked)'), function(el) {
        let vid = $(el).data('vid');
        return {
            vid_id: vid.contentDetails.videoId
    }; })
};
$.ajax({data: pd, url: 'foo.php', type: 'post'})

根据print_r($_POST['vids']),这是 PHP 收到的内容:

Array
(
    [0] => Array
        (
            [vid_id] => kCkrVN7IVbo
        )

    [1] => Array
        (
            [vid_id] => dNVxfnb8fjo
        )

    [2] => Array
        (
            [vid_id] => rJEEYTzYiAE
        )
)

一切都好。三个不同的视频。

现在是奇怪的。

foreach($_POST['vids'] as $arr) echo $arr['vid_id']."\n";

由于某种原因,这会输出:

kCkrVN7IVbo
dNVxfnb8fjo
dNVxfnb8fjo

其中一件物品已被复制,但价格昂贵,而另一件物品已被完全省略。我已经省略了所有其他代码,并且没有覆盖 $arr 或类似的东西。

如果我使用基本的 for() 循环,甚至像 array_walk() 这样的迭代回调函数,则不会发生这种情况:

array_walk($_POST['vids'], function($arr) { echo $arr['vid_id']."\n"; });

给予:

kCkrVN7IVbo
dNVxfnb8fjo
rJEEYTzYiAE

到底发生了什么?

【问题讨论】:

  • 在你展示的代码之前你做过类似的事情吗? foreach($vids as &$arr) $arr['vid_id'] = $something;
  • @AramilRey D'oh,你是对的,虽然我没想到它会导致问题。现在发布答案...

标签: javascript php arrays ajax foreach


【解决方案1】:

考虑到您在问题中显示的 foreach 循环,以及您的答案中的循环:

// First
foreach($_POST['vids'] as $i => &$arr) {
    //...
}

// Second
foreach($_POST['vids'] as $arr) echo $arr['vid_id']."\n";

第一个循环在$arr$_POST['vids'] 的每个元素之间创建一个引用,但对最后一个元素的引用永远不会取消设置,因此$arr 实际上仍然引用数组的最后一个元素

这听起来可能有点不直观,但它的意思是,当您更改 $arr 的值时,$_POST['vids'] 的最后一个元素会发生变化,因此在 $_post['vids'] 的最后一次迭代中,您实际上是在做 @ 987654328@ 哪个值是您在上一次循环迭代中指定的值。

从图形上看,类似的事情正在发生。 (这不是有效的 PHP)

$arr = [1, 2, 3, 4, 5 <=> $value] 
// This represents the last item on arr being a reference of $value (<=> is not being used as an actual operator, its representing the reference)

foreach($arr as $value) {
    echo $arr;
}
// OUTPUT:
[1, 2, 3, 4, 1 <=> $value] // $value equals the first element of the array
[1, 2, 3, 4, 2 <=> $value] // $value equals the 2nd element of the array
[1, 2, 3, 4, 3 <=> $value] // $value equals the 3rd element
[1, 2, 3, 4, 4 <=> $value] // $value equals the 4th element
[1, 2, 3, 4, 4 <=> $value] // $value equals itself (4th element)

要解决这个问题,您只需在第二个循环之前使用unset($arr) 中断引用

unset($arr);
foreach($_POST['vids'] as $arr) echo $arr['vid_id']."\n";

【讨论】:

    【解决方案2】:

    不确定这可能对其他人有帮助,但事实证明,之前在 foreach() 循环中使用了 $arr,在同一个函数中更早的时候,是罪魁祸首。

    至关重要的是,这个是通过引用分配的,即

    foreach($_POST['vids'] as $i => &$arr) {
        //...
    }
    

    由于某种原因,我不完全了解,当我后来在另一个 foreach() 分配中使用 $arr 时,这导致了问题。我知道它是从早期的参考分配中泄漏的,但是为什么要复制一个并省略另一个视频 ID?奇怪的结果...

    foreach($_POST['vids'] as $arr) echo $arr['vid_id']."\n";
    

    【讨论】:

    • 循环结束后引用变量未设置。所以它总是指$_POST['vids'] 数组的最后一个元素。随后的foreach 在每次迭代时覆盖最后一个数组桶;本质上,foreach 在每次迭代时为$arr 变量(这是一个引用)赋值。
    • 发表了我自己的答案,希望它可以帮助您了解参考是如何导致此问题的!
    猜你喜欢
    • 1970-01-01
    • 2013-04-22
    • 1970-01-01
    • 2012-04-14
    • 1970-01-01
    • 2022-06-17
    • 2015-01-31
    • 2016-07-25
    • 2011-01-03
    相关资源
    最近更新 更多