2017-02-15 2 views
-1

мне нужна помощь с определением классаООП на PHP, объекты behaivor на основе сессии

Я начинаю проект PHP 7.0, если вы не PHP гуру, но есть опыт работы с ООП, я уверен, вы также могли бы Помогите.

У меня есть следующие классы, которые помогают строить 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 | Выход для участников golder

В будущем мне может понадобиться больше «типов пользователей» и разные ссылки для них, то есть это должно быть легко изменить в будущем.

Я знаю: мне нужно, чтобы получить статус пользователя в 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 - объект пользователя в качестве настройки с конструктором

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 и смотря на то, чтобы его можно было легко осмелиться и протестировать с помощью phpunit, пытаясь отделить логин пользователя от логики «pagebuilder» так же, как и возможно

варианты 1 и 2: у меня плохое отношение к ним, они используют глобальный статус, это пахнет, разве это не так? вариант 3: я считаю, что это легко проверить. варианты 4 и 5: я думаю, что хорошая идея иметь пользователя как attitute, так как я мог использовать пользовательский статус для других методов в классе, но, с другой стороны, я беспокоюсь о семантировании, я говорю, что пользователь принадлежит к страницеbuilder ... вариант 6: Я уверен, что ваше предложение будет самым лучшим: D

спасибо за ваше время!

+0

Использование класса для сборки html в наши дни не очень хорошая практика. Рассматривали ли вы использование современной структуры? Они делают большую часть этого из коробки, поэтому вы можете сосредоточиться на своем коде сайта. – Mei

ответ

-1

Так как всегда все зависит от того, какой уровень гибкости и контроля вы хотите архивировать.

Но вы можете определенно исключить пункты 1 и 2 в качестве действительных решений.

Оба элемента опасны для использования, поскольку вы не контролируете эти данные. Любой пользователь в любое время может изменить эти данные, и в итоге вы получите сгенерированный код для неправильного пользователя. Или случилось что-то худшее.

С другой стороны вы упомянули два типа обратного шаблона управления и actaully, вы можете использовать их оба. Поэтому давайте различать, когда вы должны использовать какое решение.

  1. Это хороший подход, и он называется conif, вы планируете иметь один элемент на странице, потому что если вы хотите что-то изменить, вам нужно создать новый объект с новым пользовательским значением. Но это должен быть наиболее используемый подход для элементов, которые нужно создать один раз в течение жизненного цикла приложения.

  2. Это инъекция установки, и это также хорошее решение, но, на мой взгляд, мы должны избегать этого, почему? Потому что вам всегда нужно помнить, что если вам нужно вызвать какой-то метод, вам нужно сначала вызвать метод set. Если вы его не назовете, вы можете получить странные результаты, по крайней мере, вы можете смешать это с инсталляцией конструктора и использовать только инъекцию установщика, когда вам действительно нужно это изменить. Есть также некоторые другие обычаи, но держите их в чистоте.

  3. Это самый эластичный подход, когда дело дошло до его вызова, но вам нужен пользовательский объект во всех местах, где вы хотите вызвать этот метод. Этот подход имеет также плюсы и минусы. С одной стороны у вас есть хороший подход к одному месту, который решает некоторые проблемы, которые не могут быть решены с помощью инъекций сеттера. Вам не нужно думать ни о каком другом методе, который нужно назвать, вам просто нужно дать этому методу все параметры, которые он ожидает, и вы можете сгенерировать с помощью одного объекта меню для всех ваших пользователей (я не думаю, что это реально жизненного решения в этом случае). А с другой, вы не можете настроить этот объект для одного пользователя и отправить объект меню в другие места, чтобы просто сгенерировать его. Вам всегда нужно будет назвать это также объектом 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

Это особенно проблематично, так как он инстанцировании новый объект User непосредственно внутри функции, что сделает невозможным для имитации с PHPUnit. Иногда создание нового объекта может быть желательным поведением, но оно очень зависит от семантики того, что делает ваш класс. Поскольку вы пишете класс PageBuilder, кажется маловероятным, что также должно быть задание знать, как создать новый объект User с нуля. Эта ответственность должна относиться к чему-то еще, что посвящено этой задаче, например, какой-то класс UserService, который затем можно использовать, когда вам нужно создать/получить объект User. Таким образом, если вы когда-либо измените способ создания объекта User, например, требуя, чтобы он имел дополнительный конструктивный параметр, единственное место, которое вам нужно обновить, - это ваш класс UserService, а не все приложения.

# 2

При написании кода таким образом, вы прячась тот факт, что функция требует, чтобы существовала уже определено $user переменной. Даже если кто-то заходил в код вашей функции, чтобы увидеть, что это необходимо, им также нужно как-то узнать или разучить, какой тип объекта должен иметь переменная. Предполагая, что вы используете какой-то IDE для разработки своего кода (и вам действительно нужно), ваша среда IDE не имеет понятия, что вы потенциально называете эту функцию где-нибудь, не указав сначала $user. Это устраняет один из самых простых и мощных инструментов, которые может предоставить ваша среда IDE, чтобы уменьшить базовые ошибки кода.

# 3

ли это лучший вариант действительно зависит от конкретных сценариев использования и семантики коды, но, я бы сказал, в большинстве случаев это стиль, который вы хотите, чтобы писать.

преимущества этого подхода включают в себя:

  • Возможность воспользоваться PHPUnit фиктивных объектов во время испытаний
  • требования вашей функции сделаны совершенно ясно, для кого пытаются использовать/понять
  • Ваш 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, чтобы он был установлен на нем, а именно: 1 PageBuilder за User. Поскольку общее впечатление, которое я получаю, заключается в том, что ваш PageBuilder довольно без гражданства (т. Е. Ему не нужно отслеживать данные по нескольким вызовам функций или сохранять память о том, как это делается), это не похоже на ограничение, которое вы должны навязывать себя на будущее.

# 5

Как обратно указано выше, вы предпочли бы, чтобы это # ​​4, если вы хотите, чтобы плотно привязать User к PageBuilder на ограниченный период времени, но быть в состоянии связать различные 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 является наиболее гибкой.

Смежные вопросы