Php 将对象传递到方法中,将该对象分配给另一个对象,传入对象仍然是我传入的同一个对象

Php 将对象传递到方法中,将该对象分配给另一个对象,传入对象仍然是我传入的同一个对象,php,oop,Php,Oop,我在我的数据映射器中实现了一个小IdentityMap,它可以正确地工作,因为它知道是否已经加载了一个对象,但是它没有正确地分配内存中的对象 我已经尽可能地将代码简化为一个实体,没有数据库等。有人能解释一下为什么在lookup()方法中没有正确地将已经加载的客户对象分配给传入的客户对象吗 Customer.php class Customer { private $id; private $name; public function getId() {

我在我的数据映射器中实现了一个小IdentityMap,它可以正确地工作,因为它知道是否已经加载了一个对象,但是它没有正确地分配内存中的对象

我已经尽可能地将代码简化为一个实体,没有数据库等。有人能解释一下为什么在lookup()方法中没有正确地将已经加载的客户对象分配给传入的客户对象吗

Customer.php

class Customer {

    private $id;
    private $name;

    public function getId() {
        return $this->id;
    }
    public function setId($id) {
        $this->id = $id;
    }

    public function getName() {
        return $this->name;
    }
    public function setName($name) {
        $this->name = $name;
    }

}
class IdentityMap {

    private $customers;

    public function lookup(Customer $customer) {

        if( !array_key_exists($customer->getId(), $this->customers) ) {
            return false;
        }

        $customer = $this->customers[$customer->getId()]; //Something wrong here?

        return true;
    }

    public function add(Customer $customer) {
        $this->customers[$customer->getId()] = $customer;
    }

}
CustomerMapper

class CustomerMapper {

    private $identityMap;

    public function __construct(IdentityMap $identityMap) {
        $this->identityMap = $identityMap;
    }

    public function fetch(Customer $customer) {

        if( $this->identityMap->lookup($customer) ) {
            return true;
        }

        $this->assign($customer, array('id' => 1, 'name' => 'John'));   
    }

    private function assign(Customer $customer, Array $row) {

        $customer->setId($row['id']);
        $customer->setName($row['name']);

        $this->identityMap->add($customer); 
    }

}
IdentityMap

class Customer {

    private $id;
    private $name;

    public function getId() {
        return $this->id;
    }
    public function setId($id) {
        $this->id = $id;
    }

    public function getName() {
        return $this->name;
    }
    public function setName($name) {
        $this->name = $name;
    }

}
class IdentityMap {

    private $customers;

    public function lookup(Customer $customer) {

        if( !array_key_exists($customer->getId(), $this->customers) ) {
            return false;
        }

        $customer = $this->customers[$customer->getId()]; //Something wrong here?

        return true;
    }

    public function add(Customer $customer) {
        $this->customers[$customer->getId()] = $customer;
    }

}
当我运行此命令时:

$identityMap = new IdentityMap();
$customerMapper = new CustomerMapper($identityMap);

for( $i = 0; $i < 3; $i++ ){

    $customer = new Customer();
    $customer->setId(1);

    $customerMapper->fetch($customer);

    echo 'ID: ' . $customer->getId() . '<br>Name: ' . $customer->getName() . '<br><br>';

}
ID: 1
Name: John

ID: 1
Name:

ID: 1
Name:
为什么第二个和第三个客户对象没有名称?我相当肯定lookup()方法中的赋值部分存在问题。从昨晚开始,我就一直在做这件事,试着阅读所有的东西


我已将lookup()方法签名更改为在传入的对象前面有“&”符号,但运气不佳。

您正在使用相同的密钥(id)向查找中添加3个客户 在第一次for循环运行之后,对于for循环的其余运行,fetch方法返回true。 所以这个名字永远不会被设定

你可以试试这个:

    if( $this->identityMap->lookup($customer) ) {
        return $this->identityMap->get($customer);
    }
但是不要忘记在IdentityMap类中实现方法“get;”

问题是

当在第一个循环中调用fetch()并依次调用lookup()时,它将找不到任何值(因为identityMap为空),因此$customer将在assign()中被赋予新值(在本例中,$customer->name='John'和$customer->id='1')。这里注意,
$customer->setId(1)不提供id。无论您给出什么值,
$this->assign()
都会通过将id值指定给1来修改$customer的原始id值(通过引用传递)。您可以通过将1更改为任意值来测试它(顺便说一句,如果您将1更改为3,您将看到所有结果)

因此,在第一个循环中,$customer填充了所有要正确显示的值(id->1和name->john)

但是在第二个循环中

if( $this->identityMap->lookup($customer) ) {
    return true;
}
返回true。(id=1的customer对象位于$identityMap中;因此它不会修改作为参数传递的$customer对象。) 这意味着,函数在将name值分配给$customer之前返回

从第二个循环开始

for( $i = 0; $i < 3; $i++ ){
...
$customer->setId(1);
...
}

我们必须更深入。就像一个对象概念!试试这个,
public function lookup(Customer&$Customer)
,这样它就可以通过引用而不是通过值来传递。@MichaelPerrenoud试过了,但没有成功。还有其他建议吗?这在理论上应该行得通,不是吗?我不知道出了什么问题。我不是因为在下次运行fetch()时添加了ID=1的客户后,它会找到ID=1的客户并返回true。为什么不显示名称?这是问题的一部分。因为您没有从查找中加载数据。您只需返回true,就可以得到一个只设置了id的customer对象。在您的第一次for循环迭代中,$this->identityMap->lookup($customer)返回false并设置名称。在第二个迭代中,$this->identityMap->lookup($customer)返回true,您不设置名称,因为如果lookup()方法返回true,则应该将传入的客户对象设置为现在指向ID=1的内存中已存在的客户对象。但这似乎不起作用。谢谢你的回复。我现在让fetch()方法返回对象,而不是只返回true或false。