2013-06-03 196 views
2

我在DataMapper中實現了一個小型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: 

爲什麼第二個和第三個顧客對象沒有名字?我相當確定lookup()方法中的分配部分存在問題。自從昨晚嘗試和閱讀所有內容以來,我一直都在這裏。

我已將lookup()方法簽名更改爲在傳入的對象前面有「&」符號,但沒有運氣。

+1

我們必須更深入。就像一個觀點! – Dropout

+0

試試這個,'公共函數查找(Customer&$ customer)',以便它通過引用而不是按值傳遞。 –

+0

@MichaelPerrenoud嘗試過,沒有運氣。還有其他建議嗎?它應該在理論上工作,但不應該呢?我不知道什麼是錯的。 – ibanore

回答

1

問題是

當取()被調用第一個循環並且它依次調用lookup()它將找不到任何值(因爲identityMap爲空),因此$ customer將在assign()中獲得新值(在這種情況下,$ customer-> name ='John '和$ customer-> id ='1')。請注意,$customer->setId(1);不提供此ID。無論您給$this->assign()的任何值$this->assign()通過將id值指定爲1來修改$ customer的原始id值(通過引用傳遞)。您可以通過將1更改爲任意值來測試它(如果將1更改爲3,則會顯示所有結果)。

所以在第一循環$客戶填充了所有正確顯示(ID-> 1,名稱爲 - >「約翰」)的值

但在第二循環

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

回報真正。 (id = 1的客戶對象位於$ identityMap中;因此它不會修改作爲參數傳遞的$ customer對象。) 這意味着函數在名稱值分配給$ customer之前返回。

因此,從第二循環

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

新創建的$客戶對象將不會被分配的名稱值開始。這就是爲什麼它僅以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')); 
+0

感謝您的回覆。我現在讓我的fetch()方法返回對象,而不是僅僅返回true或false。 – ibanore

1

在第一次for循環運行之後,您將3個客戶添加到查找中,使用相同的鍵(id) ,fetch方法對其餘的for循環運行返回true。 所以這個名字永遠不會被設置。

你可以試試這個:

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

但是不要忘記實現在IdentityMap類中的方法 「搞定」;)

+0

我不是因爲一旦下次運行fetch()時添加了ID = 1的客戶,它就會找到ID = 1的客戶並返回true。 – ibanore

+0

爲什麼不顯示名稱?這是問題的一部分。 – Bere

+0

因爲您不會從查找中加載數據。你只需返回true,你擁有的只是一個只有id集的客戶對象。 –