2

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

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

客户.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 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); 
    }

}

身份映射

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() 方法签名更改为在传入的对象前面有“&”符号,但没有运气。

4

2 回答 2

1

问题是

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

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

但在第二个循环中

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

返回真。(id = 1 的客户对象在 $identityMap 中找到;因此它不会修改作为参数传递的 $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'));
于 2013-06-03T13:46:08.527 回答
1

在第一次 for 循环运行后,您将 3 个客户添加到具有相同键 (id) 的查找中,对于其余的 for 循环运行,fetch 方法返回 true。所以永远不会设置名称。

你可以试试这个:

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

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

于 2013-06-03T12:38:05.247 回答