在foreach循环之后覆盖数组

时间:2013-02-28 09:25:23

标签: php arrays foreach overwrite

我正在尝试将包含sql结果集中元素的对象推送到数组中。我的代码就像:

$data = array();
$sql = "SELECT id,type,name,username FROM users";
foreach ($conn->query($sql) as $row) { 
    $this->set_id($row['id']);
    $this->set_type($row['type']);
    $this->set_username($row['username']);
    $this->set_password($row['password']);

    $data[] = $this;
}

我的结果集是正确的,但是在foreach循环结束后,我用最后一个记录集的值覆盖了我的数组单元格。例如,如果我有这些结果{1,'type1','user','pass'}{2,'type2','foo','bar'},当我在循环中print_r my $data数组时,我只得到第二个结果集重复两次。我做错了什么?

4 个答案:

答案 0 :(得分:3)

在实例方法中,$this总是引用当前的类实例;在每次循环迭代中,您修改实例本身,然后将其添加到$data;但是在分配时,不会复制,而是添加对同一实例的引用。

最后,你有一个在每个索引处都有相同对象的数组。

您需要在每次循环迭代时创建一个新的类实例:

foreach ($conn->query($sql) as $row) { 
    $obj = new self; // create new instance of ourselves

    $obj->set_id($row['id']);
    $obj->set_type($row['type']);
    $obj->set_username($row['username']);
    $obj->set_password($row['password']);

    $data[] = $obj;
}

这是个人建议,但我会将此代码移到静态方法或单独的类中。

答案 1 :(得分:1)

对象不能像那样工作,$this始终是同一个对象,您可以在每次迭代中对其进行修改。您可以每次都使用$data[] = clone $this;来创建一个新实例,但这是糟糕的类设计,最好将您的课程分成两个单独的类。

一个类不应该有多个职责,但你的职责一次充当数据库网关和域模型。

答案 2 :(得分:0)

无论$this是什么,它都是对某种对象的引用。因此,当您更新该对象时,数组中保存的所有引用仍然指向同一个对象。您必须在每个循环中定义一个新对象。

答案 3 :(得分:0)

您不是在迭代开始时创建新的$this对象。在两次迭代中,您都要修改同一个对象,并将其两次添加到数组中。处理对象时,它们通过引用传递,这意味着您不会向数组添加副本,而是添加对$ this变量的引用。也许您应该将$row添加到数组中,但您仍然会将保存的数据覆盖到$this

您也可以使用clone关键字(请参阅manual)来保存对象的副本。

更多信息:http://php.net/manual/en/language.references.php