把对象传入方法,把那个对象赋值给另一个对象,传入的对象还是我传入的那个对象


Pass object into method, assign that object to another object, passed in object still the same object I passed in

我实现了一个小的IdentityMap到我的DataMappers,它的工作方式正确,它知道如果一个对象已经加载,但它不分配内存对象正确。

我已经简化了代码,尽可能多的我可以(它并不复杂)到一个实体,没有数据库等。有人可以解释为什么在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()方法的签名,在传入的对象前面有"&"符号。

问题是

当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。(在$identityMap中找到id =1的客户对象;因此,它没有修改作为参数传递的$customer对象。)这意味着,函数在name value被赋值给$customer之前返回。

从第二个循环开始

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

新创建的$customer对象将不会被分配name value。这就是为什么它只显示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'));

您正在使用相同的键(id)向查找添加3个客户在第一次for循环运行之后,fetch方法在for循环运行的其余部分返回true。因此,该名称将永远不会被设置。

你可以试试:

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

但是不要忘记在IdentityMap类中实现"get"方法;)