2011-06-01 134 views
15

我一直在PHP開發一段時間,但直到最近才切換到OOP方法。這一直此起彼伏,我面向對象的最佳實踐(特別是PHP)

的一個問題是「有多遠」去與面向對象的東西,特別是在執行速度方面和內存資源等

例如,假設我有2個對象,用戶和列表

列表總是鏈接到一個單獨的用戶。 UserId是Listing的一個屬性,所以我知道它與哪個用戶相關。 偶爾,在Listing方法中,我需要訪問相關用戶的單個屬性。

據我所見(請告知如果沒有的話)我有3個選項可以實現這個功能。

  1. 創建一個新的用戶對象,並通過$用戶訪問培訓相關屬性格式 - >利人

  2. 進行必要的財產清單的本地屬性和填充此房源被初始化時(例如,通過SQL JOIN )

  3. 查詢數據庫直接檢索用戶的通過用戶ID所需要的屬性

它似乎對我來說,選項1更加嚴格地遵守OOP規則,但由於初始化整個對象只是爲了檢索1個屬性而具有性能命中。選項3將是最少的內存密集型,但完全避開了OOP。另外,就創建時填充對象而言,我的大多數對象在初始化後不久(通過只需要1個DB查詢)就通過一個「填充」方法獲得大部分屬性。這通常會被認爲是最佳實踐,還是最好使用單獨的方法來獲得這些屬性,並在需要時填充?

我意識到這可能沒有「正確」的答案,但任何人都可以提供有關處理這種情況的最佳方法的建議嗎?

非常感謝 尼克

+0

你可以一舉(1 + 2)儘快爲他們登錄(假設登錄),填充它,並把它存儲爲對象(S)獲取有關用戶的一切,那麼就保持它周圍,以獲取有關信息直到他們註銷然後銷燬該對象。我想這就是我應該去做的。 – robx 2011-06-01 07:48:51

+2

除非你異形這三種方法,找到一個signigicantly阻礙性能,你不應該現在操心內存消耗和處理速度。只要使用有用的東西。 – Gordon 2011-06-01 07:49:40

+0

如何使User對象成爲Listing對象的屬性,而不僅僅是UserId? – prasopes 2011-06-01 07:50:12

回答

2

我肯定更喜歡選項1選項2不跟在別人後面OOP的想法,因爲用戶信息是不是你的上市的一部分,所以把它放在一個單獨的對象。

請記住以下規則記:

  1. 加載對象沒有其關係的一次。
  2. 如果您需要相關對象加載它在你按照規則1

許多奧姆斯以這種方式工作需要的時間,例如學說(http://www.doctrine-project.org)。它被稱爲延遲加載。

當你需要一個對象的一個​​屬性時,你會發現自己加載了同一對象的第二個屬性,進一步的一些行。在很多情況下,你會發現自己在一個完整的腳本中爲一個對象做了大量的數據庫查詢。

+0

但有一點意見:只有在不確定需要鏈接對象時才使用延遲加載。如果你已經知道你會需要它們,那麼一次性加載它們 - 當然不是所有的,只是你知道你需要的那些。對於報告(如打印報告),我主要使用直接查詢或視圖,因爲它們中的大多數需要彙總結果。 – wimvds 2011-06-01 08:51:55

+0

感謝大家提供的有用評論 - 懶加載對我來說是一個全新的概念,我將着眼於探索。我認爲我在這裏學到的主要觀點是專注於首先維護正確的面向對象的實踐,然後根據性能問題在後面應用其他技術,例如延遲加載。 – Nick 2011-06-01 09:11:53

+0

貶低我的人可以給出一個理由。我願意聽到你的論點。 – 2011-06-01 13:11:17

0

我相信你需要看一看到數據傳輸對象的設計模式:

視圖(頁)應該接受它必須是不一樣的那些數據傳輸對象你的數據訪問層是如何工作的。

通過一些參數化,您的業務層可能會返回具有由數據訪問層返回的一個或多個對象的特定集合的DTO。

例如,如果您想列出用戶,也許您想知道他們的「組標識符」,「用戶標識符」和「全名」。

用戶組的標識符來自某個Group對象,而用戶的標識符和全名來自某個User對象,最後,UserDto對象將具有User和Group對象的屬性,這些屬性是某些用戶界面視圖需要的顯示用戶列表。

1

選項1是首選的OOP方式。

另外,在PHP中,你可以編寫一個包裝對象,它只包含user_id和你需要的屬性。

而當調用方法或訪問其他屬性時,您可以加載並啓動真實的用戶對象。

這可以實現__get(),__set()和__call()方法。

這樣,您可以在需要時從用戶對象訪問所有OOP善良的同時,優化Listing對象的查詢和內存使用情況。

代碼看起來應該沿着線的東西:

class LazyObject { 

    private 
    $propertySubset = array(), 
    $realObject; 


function __call($method, $args) { 
    if ($this->realObject === null) { 
     $this->initRealObject(); 
    } 
    return call_user_func_array(array($this->realObject, $method), $args); 
    } 

    // __get, __set and initRealObject implementation goes here 

}

注意事項

  • 您可以使用引用:myMethod(&$ref)$shortcut = &$object->prop不會工作
  • 你需要手動檢查你是否填寫了t他包裝了足夠的屬性。 沒有足夠的屬性會導致查詢的分配,並且包裝只會減慢查詢速度。除非您在lazyObject實現它們

PS接口(如ArrayAccess接口)

  • 用法將不起作用。
    這應該被認爲是一種最佳化黑客攻擊。所以只有在性能成爲問題時才實施這一點;

  • 1

    在您選擇第一個選項之前,我會建議您繼續嘗試將簡單的對象模型應用於存儲在數據庫中的數據,這可能會帶來很多麻煩。

    爲了以防讀這有什麼,我告訴一個想法: "Why did object oriented databases fail"

    中有你說兩句,沒有一個「正確」的答案。但是,我們可以這樣說:

    在一個面向對象的理想的好習慣,在$上市對象應是代表上市的用戶對象$ listing->用戶屬性。爲了獲得更好的性能,只要實例化$ listing,就不應該實例化此User對象。在Java傳統編碼中,您將擁有一個方法 - > getUser()。在PHP中,只要調用 - > user屬性,就可以實例化該對象。

    但是,當你只需要一個屬性中獲取完整的用戶信息,這可能會花費太多的無用數據流。如果您的代碼想要一次處理大量的清單對象,情況尤其如此。

    如果是這樣,那麼你必須移動的方式與理想對象模型一點點,以便更加貼近您的業務流程。然後只檢索您需要的用戶資產,這可能是一個很好的折中方案。例如:$ listing-> getUserProp1()。如果將來可能需要其他用戶屬性,則可以將該方法更改爲$ listing-> getUserProprty('prop1')。

    但這一選擇是好的只有當您需要的用戶屬性的時候。如果實際上每當擁有一個Listing對象時都需要它,那麼最好將User屬性與其他Listing屬性一起初始化。這是你的選擇#2。這似乎是一個非常好的解決方案,可以將數據流量最小化,並且如果您不需要附近的其他用戶信息。