我正在尝试将包含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
数组时,我只得到第二个结果集重复两次。我做错了什么?
答案 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)来保存对象的副本。