3

我正在尝试将包含来自 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'}当我$data在循环之外打印我的数组时,我只会得到第二个结果集重复两次。我究竟做错了什么?

4

4 回答 4

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;
}

这是个人建议,但我要么将此代码移动到静态方法中,要么完全移动到单独的类中。

于 2013-02-28T09:27:44.967 回答
1

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

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

于 2013-02-28T09:32:07.130 回答
0

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

于 2013-02-28T09:28:35.180 回答
0

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

您还可以使用clone关键字(参见手册)来保存对象的副本。

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

于 2013-02-28T09:28:48.683 回答