PHP循环遍历对象数组给出了意外结果

4
我有以下PHP代码来为每个帖子设置parentId。 每个数据的parentId都变成了最后一个帖子的ID。 我的逻辑有什么问题吗?
顺便说一下,如果我将其更改为数组,则一切都变得正常。请帮忙!
$data = array(
    (object)array('name' => 'myname')
);
$posts = array(
    (object)array('ID' => 1, 'data'=>$data),
    (object)array('ID' => 2, 'data'=>$data),
    (object)array('ID' => 3, 'data'=>$data)
);
foreach($posts as &$post){
    $post->data[0]->parentId = $post->ID;
}
print '<pre>';print_r($posts);die;
die;

结果:

Array
(
    [0] => stdClass Object
        (
            [ID] => 1
            [data] => Array
                (
                    [0] => stdClass Object
                        (
                            [name] => myname
                            [parentId] => 3 // expect to be 1
                        )

                )

        )

    [1] => stdClass Object
        (
            [ID] => 2
            [data] => Array
                (
                    [0] => stdClass Object
                        (
                            [name] => myname
                            [parentId] => 3 // expect to be 2 !!!
                        )

                )

        )

    [2] => stdClass Object
        (
            [ID] => 3
            [data] => Array
                (
                    [0] => stdClass Object
                        (
                            [name] => myname
                            [parentId] => 3
                        )

                )

        )

)

请尝试访问 http://phpfiddle.org/main/code/yq2-jv3。 - user1646111
2个回答

5

综合考虑,真正的问题在于,仔细查看您的代码后,您设置data属性的方式。自PHP5以来,默认情况下对象通过引用传递/赋值。还记得PHP4时代吗?($newInstance = &new SomeClass();),现在PHP5使用引用来处理对象,因此当您执行以下操作时:

$data = array(
    (object)array('name' => 'myname')//create object
);

然后,所有三个对象都被分配了同一个对象(通过引用!),因此如果您在第一次更改时对其进行更改,则所有三个实例都将反映相同的更改! 我最近在这里发布了一篇关于循环中引用的详细答案,这可能值得一看,因为通过引用循环不是您处理业务的最佳方式。
一些代码审查:
与其单独构建所有这些数组并将它们转换为对象,我只会这样做:
$data = array(
    array('name' => 'myname')
);
$posts = array(
    array('ID' => 1, 'data'=>$data),
    array('ID' => 2, 'data'=>$data),
    array('ID' => 3, 'data'=>$data)
);
foreach($posts as $k => $post)
{
    $posts[$k]['data'][0]['parentId'] = $posts[$k]['ID'];
}
$posts = json_decode(json_encode($posts));//turns everything into objects
print_r($posts);

起初,使用json_encode来编码,再使用json_decode来解码可能看起来效率低下,但是json_decode默认返回对象而不是关联数组。我最近运行了一些测试脚本,结果发现:编码-解码方法比将每个关联数组转换更快...

3

好的,我误解了你的问题,由于您重复使用数据对象,导致出现引用问题,可以通过使用克隆来避免这种情况,如下所示:

<?php

$data = (object) array('name' => 'myname');

$posts = array(
    (object) array('ID' => 1, 'data'=> array(clone $data)),
    (object) array('ID' => 2, 'data'=> array(clone $data)),
    (object) array('ID' => 3, 'data'=> array(clone $data))
);

foreach($posts as $postKey => $post){
    $posts[$postKey]->data[0]->parentId = $posts[$postKey]->ID;
}
print '<pre>';
print_r($posts); 

2
你错了,他通过引用传递进行操作,因此他正在处理数组内部的数据。 - Soundz
1
与其克隆,直到数据属性被赋值后再使用对象的方式更加高效且更容易。 - Elias Van Ootegem
是的 - 我只是不想为这个例子更改传入的数据,如果你当然可以避免对象和数组之间的所有混淆,那就更好了。 - Hannes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接