2017-02-15 56 views
-1

我需要一些幫助類定義OOP在PHP,基於會話

我開始一個PHP 7.0的項目,如果你不是一個PHP的大師,但有OOP經驗,我相信你也可以反對behaivor幫幫我。

我有以下類,有助於建立一個HTML頁面

interface PageBuilderInterface 
{ 
    public function getHTMLPage(): string; 
    public function getHead(): string; 
    public function getBody(): string; 
    public function getMenu(): string; 
    public function getMainArea(): string; 
    public function getFooter(): string; 
} 



class PageBuilder implements PageBuilderInterface 
{ 

    public function getHTMLPage(): string 
    { 
     return "<!doctype html><html>" . 
        $this->getHead() . 
        $this->getBody() 
       "</html>"; 
    } 

    public function getHead(): string 
    { 
     return '<meta charset="utf-8"> 
       <title>Page Title</title>'; 
    } 


    public function getBody(): string 
    { 
     return "<body>" . 
        $this->getMenu() . 
        $this->getMainArea() . 
        $this->getFooter() . 
       "</body>"; 
    } 

    public function getMenu(): string 
    { 
     return '<a href="index.php">Home</a> | 
       <a href="login.php">Login</a> | 
       <a href="register.php">Become Member</a> '; 
    } 

    public function getMainArea(): string 
    { 
     return '<h1>Main Content Here</h1> 
       <p>Loren Ipsun...</p>'; 
    } 

    public function getFooter(): string 
    { 
     return '<div>Footer Page Here</div>'; 
    } 
} 

用法:

$page = new PageBuilder(); 
echo $page->getHTMLPage(); 

它是簡單的作品。

現在,我有了一個新的要求:根據用戶會話,一些方法應該會有很大的不同,例如我們有「訪客」,「基本成員」和「黃金會員」用戶類型。主菜單上

鏈接是針對每種類型的構件的不同,並且應該是能夠顯示不同的信息的每個成員(例如消息,信用餘額或任何其它信息)

所以,

PageBuilder :: getMenu()

應返回一些鏈接,如

首頁|登錄|成爲訪問者會員 主頁|消息|註銷基本會員 首頁|消息|餘額$ 208.23 |退出高爾夫球員

未來我可能需要更多的「用戶類型」和不同的鏈接,這是對未來應該很容易改變的方式。

我知道:我確實需要得到內部使用getMenu()方法的用戶狀態,但下列選項不知道至極是最好的:

1 - 從會議

public function getMenu(): string 
{ 
    $user = new User($_SESSION['id_user']); 
    $links = $user->getLinks(); // perhaps an array with links 

    return doSomeFormatToLinks($links); 
} 

2創建用戶 - 全局用戶對象

public function getMenu(): string 
{ global $user; 
    $links = $user->getLinks(); 

/* .... build html links here */ 
} 

3 - 作爲參數

public function getMenu(User $user): string 
{ 
    $links = $user->getLinks(); 
} 

4 - 用戶對象作爲類attibute與構造

class PageBuilder implements PageBuilderInterface 
{ 
    private $user; 

    public function __construct(User $user) 
    { 
     $this->user = $user 
    } 
} 

5設置它 - 比4相似,但與設定器

class PageBuilder implements PageBuilderInterface 
{ 
    private $user; 

    public function __construct() 
    { 
     $this->user = $user 
    } 

    public function setUser($this->user = $user) 
    { 
     $this->user = $user; 
     return $this; 
    } 
} 

6 - 其他選項?

我在尋找最好的選擇,注意SOLID原則,並期望以易於模擬和測試的方式設計它,試圖將「用戶」登錄從「pagebuilder」邏輯中分離出來可能

選項1和2:我對他們有不好的感覺,他們使用全球地位,它是聞到,是不是? 選項3:我覺得很容易測試。 選項4和5:我認爲將用戶作爲屬性是個不錯的主意,因爲我可以在課程中使用其他方法的用戶狀態,但另一方面,我擔心它是光鮮的,我說的是用戶是屬於一個頁面製造商... 選項6:我相信你的建議將是最好的:D

感謝您的時間!

+0

這些天使用一個類來構建html並不是很好的做法。你有沒有考慮過使用現代框架?他們開箱即可完成大部分工作,因此您可以專注於您的網站代碼。 – Mei

回答

-1

所以,一切都取決於你想存檔的靈活性和控制水平。

但是,您絕對可以排除點1和點2作爲有效的解決方案。

這兩個元素都有風險使用,因爲您沒有這些數據的任何控制權。任何人隨時都可以更改這些數據,並且最終會爲錯誤的用戶生成代碼。或者最糟糕的事會發生。

另一方面,你已經提到了兩種類型的逆控制模式,並可以使用兩種類型的逆控制模式。因此,讓我們區分何時應使用哪種解決方案。

  1. 這是一個不錯的方法,它被稱爲conif你計劃每頁有一個元素,因爲如果你想改變某些東西,你需要用新的用戶值創建新的對象。但它應該是您在應用程序生命週期中一次創建的元素的最常用方法。

  2. 這是setter注入,這也是一個很好的解決方案,但在我看來,我們應該避免這一個,爲什麼?因爲你需要時刻記住,如果你需要調用一些方法,你需要先調用set方法。如果你不會調用它,你可能會得到奇怪的結果,至少你可以將它與構造函數注入混合使用,並且只有在你真的需要改變它時才使用setter注入。還有一些其他用法,但保持清潔。

  3. 它是調用它時最具彈性的方法,但您需要在您想調用此方法的所有地方使用用戶對象。這種方法也有利有弊。從一方面來說,你有一個很好的解決某些無法用setter注射解決的問題的方法。你不需要考慮任何其他被調用的方法,只需要給這個方法所需的所有參數,並且你可以爲所有用戶生成一個對象菜單(我不認爲這是真的生活中的解決方案)。另一方面,您不能爲一個用戶設置此對象,並將菜單對象發送到其他位置以生成它。您始終需要將其稱爲User對象。

因此,每種方法都適用於3,4,5,但每個方法都可以解決其他一些情況。在我看來,對於這個特定的情況,我會用構造函數注入。

class PageBuilder implements PageBuilderInterface 
{ 
    private $user; 

    public function __construct(User $user) 
    { 
     $this->user = $user 
    } 

    public function getMenu(User $user): string 
    { 
     return $user->getLinks(); 
    } 

}

我希望這將有助於瞭解這些差異。

-1

你的感覺正確,選項#1和#2不是你要找的。您使用全局變量創建的任何對象都會立即違反封裝原則,並且會使您的代碼更加難以測試。

#1

這是特別有問題的,因爲它是在函數,這將使得不可能使用PHPUnit嘲笑內直接實例化新User對象。有時候創建一個新對象可能是一個理想的行爲,但它非常依賴於你的類正在做什麼的語義。由於您正在編寫PageBuilder課程,因此知道如何從頭開始創建新的User對象似乎不太可能。這個責任應該落在專門用於該任務的其他事物上,比如某種類型的UserService類,然後您可以在需要創建/獲取User對象時使用該類。這樣,如果您更改構建對象的方式(例如要求它具有額外的構造參數),則唯一需要更新的地方是您的類,而不是遍佈整個應用程序。

#2

通過這種方式編寫代碼,你躲着走,你的功能要求那裏是一個已經定義$user變量的事實。即使有人確實瞭解了你的函數的代碼,以確定它是否需要,他們也不得不以某種方式知道或試圖確定該變量所持有的對象類型。假設您使用某種IDE來開發代碼(並且您確實應該),IDE將不知道您可能會在某處首先定義$user而將該函數調用到某處。這會消除IDE可以幫助減少基本代碼錯誤的最基本和最強大的工具之一。

#3

這是否是最佳的選擇實際上取決於精確的使用場景和你的代碼的語義,但是,我會在大多數情況下,說這是你將要在寫的風格。

這種方法的優點包括:

  • 能力採取在測試過程中的優勢PHPUnit的mock對象
  • 你的函數的要求是由非常清楚任何人嘗試使用/理解
  • PageBuilder對象是可以重複使用多個User小號

我的意思是最後的一點是,你可以使用相同的PageBuilder對象儘可能多User對象,只要你喜歡。假設有一種情況,您想循環遍歷系統中的每個用戶,並根據每個用戶生成一些輸出。使用這種方法將可能讓你做到以下幾點:

$pageBuilder = new PageBuilder(); 
$pageContent = ''; 

foreach ($users as $user) { 
    $pageContent .= $pageBuilder->getUserContent($user); 
} 

echo $pageContent; 

的選擇,如果你用4號去會是這樣的:

$pageContent = ''; 

foreach ($users as $user) { 
    $pageBuilder = new PageBuilder($user); 
    $pageContent .= $pageBuilder->getUserContent(); 
} 

echo $pageContent; 

在創建一個新的PageBuilder對象的開銷可能不在這種情況下尤其高,這種模式通常更糟,無論如何都會產生額外的開銷。如果你的PageBuilder對象碰巧有一個沉重的構造函數(也許有一天你需要改變它,以便它在數據庫準備好之前需要來自數據庫的數據),那麼你可能會遭受合理的性能影響。

#4

,如果你曾經爲PageBuilder對象的一些特殊需要和User對象變爲緊密結合在一起的話,你只要使用這種方法。在這種情況下,這種方法會比#5更準確IF您正在設計PageBuilder類,使得沒有User首先被設置沒有它的公共功能將工作,你不希望它其他任何User對象都可以在其上設置,即每個User只需1 PageBuilder。由於我得到的整體印象是您的PageBuilder是非常無狀態的(即它不需要跟蹤跨多個函數調用的數據或保留它所做的記憶),這似乎不是你應該施加的限制自己的未來。

#5

中逆如上所述,您希望這#4,如果你想緊緊地綁定UserPageBuilder在有限的時間,但隨後能夠在以後結合不同User日期。這使得它與#3中給出的例子非常相似。

$pageContent = ''; 
$pageBuilder = new PageBuilder(); 

foreach ($users as $user) { 
    $pageBuilder->setUser($user); 
    $pageContent .= $pageBuilder->getUserContent(); 
} 

echo $pageContent; 

這完全取決於你的使用情況,但在特定情況下,我會說這還是不如#3,如果你不要求的能力,內部跟蹤多個函數調用之間的數據。

TLDR:#1和#2不好,從外面很難理解,很難測試,很難維護。 #3,#4和#5都是可測試的,並且可能可行,具體取決於您的整體應用程序結構和邏輯,但一般來說,#3的模式是最靈活的。