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

时间:2013-06-03 12:29:12

标签: php oop

我在我的DataMappers中实现了一个小的IdentityMap,它能够正确地知道某个对象是否已经被加载但是它没有正确地分配内存对象。

我已尽可能地将代码简化为(无论如何并不复杂)一个实体,没有数据库等。有人可以解释为什么在lookup()方法中没有正确地将已经加载的Customer对象分配给传入Customer对象?

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

}

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 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:

为什么第二个和第三个Customer对象没有名称?我很确定lookup()方法中的赋值部分存在问题。自从昨晚尝试和阅读所有内容以来,我一直在这里。

我已将lookup()方法签名更改为“&amp;”没有运气的传递对象面前的符号。

2 个答案:

答案 0 :(得分:1)

您使用相同的密钥(ID)向查找中添加3个客户 在第一个for循环运行之后,fetch方法在for循环运行的其余部分返回true。 所以永远不会设置名称。

你可以试试这个:

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

但是别忘了在IdentityMap Class中实现方法“get”;)

答案 1 :(得分:1)

问题是

当调用fetch()时,在第一个循环中它又调用lookup(),它将找不到任何值(因为identityMap为空),结果$ customer将在assign()中给出新值(in这种情况是$ customer-&gt; name ='John'和$ customer-&gt; id ='1')。请注意$customer->setId(1);不提供ID。无论您给出什么值$this->assign(),都可以通过将id值指定为1来修改$ customer的原始id值(通过引用传递)。您可以通过将1更改为任意值来测试它(如果您将1更改为3,则为BTW) ,你会看到所有结果。)

所以在第一个循环中,$ customer填充了正确显示的所有值(id-&gt; 1和name-&gt;'john')

但是在第二个循环中

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

返回true。 (在= identityMap中找到id = 1的customer对象;因此它不会修改作为参数传递的$ customer对象。) 这意味着,函数在名称值分配给$ customer之前返回。

从第二个循环开始

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

新创建的$ customer对象不会被赋予名称值。这就是它仅显示id值的原因。

您可以通过应用以下更改来解决上述问题:

function lookup(){
...
return $customer; // instead of returning true
}

function fetch(){
...
$c=$this->identityMap->lookup($customer);//
if($c){
    $customer->name=$c->getName();
}

// if you like the new objects hold their original value do the following
$this->assign($customer, array('id' => $customer->getId(), 'name' => 'John'));