Выбор классов для использования в дизайне ООП PHP - PullRequest
7 голосов
/ 31 декабря 2011

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

Поэтому я решил попробовать перекодировать сайт с нуля с теми же функциями, но в формате ООП.

У меня проблема с выбором классов, я понимаю ООП и то, как оно должно работать, но всегда, кажется, возникают проблемы с началом работы. Я не уверен, должен ли я пытаться создавать функции для таких классов, как пользовательский класс с входом в систему пользовательской функции, или же пользовательский класс должен просто добавлять / обновлять / показывать пользовательские данные, и часть регистрации будет лучше в системе класс

В данный момент я начал со следующего класса и функций, но подходят ли они к этой категории?

<?
class User {

    var $userId,
        $username,
        $userRole,
        $userEmail;

    function isLoggedIn(){

    }

    function login($postusername, $postpassword)
    {

    }

    function increaseLoginCount(){

    }

    function logout(){

    }
}
?>

Тогда я мог бы получить что-то вроде следующего в page.php .. (класс подключения не показан)

<?
$db = new Connect;
$db->connect();

$user = new User;

if(!$user->isLoggedIn())
{
    echo "Please Log In.";

    if($_POST['user'])
    {
        $user->login($_POST['username'], $_POST['password']);
    }
}
else
{
    if($_POST['logout'])
    {
        $user->logout();
        exit;   
    }

    echo $user->username." Logged In.<br />";
}
?>

Но тогда на сайте были бы страницы для отображения категорий игр, и я не знаю, куда поместилась бы функция displayGames (), поскольку это не отдельная игра, поэтому не пошел бы в класс 'Game'?

Я пытался найти примеры «реального мира», но php-код, показывающий мне, как заставить слона изменить цвет или танец, не очень помогает ...

Ответы [ 4 ]

9 голосов
/ 03 января 2012

Давайте начнем с некоторого текстового анализа, выделенного мной:

Я управляю аркадным сайтом и более в последние несколько лет

Подумайте о том, сколько вы способны справиться и с чем вы имеете дело. Также поймите, что за эти годы вы получили специальные знания о запущенных аркадных сайтах . Вы приобрели профессию в своем районе. Никогда не недооценивайте свою собственную позицию и активы, это база, с которой вы работаете, и вы внесете изменения. Это включает в себя базу пользователей вашего сайта.

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

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

Поэтому я решил попробовать и перекодировать сайт с нуля с теми же функциями , но в формате ООП.

Говорят, что можно было бы использовать методы ООП для создания программного обеспечения многократного использования, есть (и не может быть) доказательство этого.

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

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

В PHP возможно смешать процедурный и объектно-ориентированный стиль, что может быть особенно полезно, если у вас есть устаревший код (общее определение устаревший код - это код с / o автоматизированные тесты).

У меня проблема с выбором классов ,

Я пытаюсь перефразировать это: Для чего писать классы для?

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

Начало всегда самый сложный шаг. Вы готовы принять решение сейчас, но не можете заглядывать в будущее. Уменьшите риск, устранив наиболее рискованную часть. Вы, вероятно, начали задавать вопрос здесь, чтобы получить обратную связь для обоснования своих решений, но это, вероятно, не уменьшит нагрузку и может привести к путанице. Однако получить образование чаще всего хорошо.

Я не уверен должен ли я пытаться создать функции для классов, таких как пользовательский класс с функцией входа в систему, или пользовательский класс должен просто добавлять / обновлять / показать детали пользователя и часть лога будет лучше в системном классе?

Это сильно зависит от характера вашего приложения и характера пользователя. Вероятно, большая часть вашего сценария должна знать только, является ли пользователь конкретным или анонимным (анонимный пользователь не вошел в систему), его идентификатор, имя или псевдоним.

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

Каждый из ваших скриптов / команд, который имеет объект контроллера приложения, может запрашивать пользователя и просто взаимодействовать с ним.

Однако это просто технически говоря. Примите во внимание тот факт, что вы не уверены, работайте с этой информацией. Постарайтесь лучше сформулировать свою конкретную проблему, перечислить плюсы и минусы для конкретного способа ее решения, еще раз отойти от конкретного кода, прежде чем начинать кодировать. Тогда сравните плюсы и минусы. Постарайтесь сделать вещи более простыми и менее сложными.

Вероятно, запишите простыми словами, что должно происходить вместо написания кода.

На данный момент Я начал со следующего класса и функций , но соответствуют ли они этой категории **? **

Ваш код довольно прост, поэтому о нем сложно сказать, тем более, что я не знаю, какой у вас аркадный сайт (и какую категорию вы пишете). Это все еще хорошо для примера, вероятно. На ваших занятиях видно, что вы тесно интегрируете все друг с другом.

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

 $application->getDB();

Поскольку пользователь является таким центральным субъектом в каждом приложении, он должен иметь очень простой интерфейс. Все детали славы об аутентификации, получении свойств пользователей и т. Д. Должны быть делегированы в другой класс / компонент, чтобы вы могли изменить реализацию, где хранятся пользователи и как они аутентифицируются:

 /**
  * @package command.modules.games
  */
 function ListGamesCommand(Request $request, Response $response)
 {
     $application = $request->getApplication();
     $user = $application->getSession()->getUser();
     $games = $application->getModels()->build('games');
     $games = $games->findByUser($user);
     $response->setProp('games', $games);
 }

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

Создайте фабрику, которая производит пользователя для объекта приложения - все, что ему понадобится сейчас или в будущем (см. Две груды объектов в Чистые беседы по коду - Наследование, Полиморфизм И тестирование ). Если вам нужна аутентификация, добавьте ее в объект сеанса или интерфейс объекта пользователя.

В любом случае сама аутентификация будет реализована в своем собственном классе, Authenticator. Таким образом, вы также можете просмотреть свои интерфейсы позже, перенеся вызов аутентификации из сеанса в пользователя или что-то еще. Только небольшая часть ваших команд должна будет справиться с этой конкретной задачей, и, поскольку весь новый код проходит автоматические тесты, поскольку вы хотите переписать и извлечь выгоду из ООП, вы убедились, что все места покрыты и должным образом переработаны.

То же самое верно для доступа к переменным запроса. Если вы хотите использовать преимущества ООП - который тесно связан с косвенным обращением (и каждый уровень косвенного доступа имеет свою цену) - вы должны прежде всего заставить свои базовые классы работать с конкретными данными, а не с какими-либо данными (например, глобальные и суперглобальные, я видел $_POST в вашем примере кода.

Итак, включите ваш новый код для обработки запроса и доставки ответа (Ввод - Обработка - Вывод):

$request  = new Request($_SERVER, $_GET, $_POST, $_COOKIE, $_FILES, $_ENV);
$response = new Response;

Пример взят из BankAccount - Пример приложения, используемого для обучения PHPUnit

Теперь все, что ниже, может работать с объектами Request и Response - обрабатывать ввод и превращать его в вывод. команда домена (ваши скрипты / команды, которые делают это) больше не нужно заботиться о извлечении ввода из HTTP-запроса, например, используя $_POST или $_GET, они могут получить его непосредственно из Request - или если вы пишете собственный класс команд - это может быть еще более адаптировано. А некоторые команды могут работать с собственными запросами и ответами.

Следующая большая тема - это пользовательский интерфейс. Вы пишете, что хотите:

Я решил попробовать перекодировать сайт с нуля с теми же функциями, но в формате ООП.

Я уже писал, что такое может быть бесплодным. Чтобы воспользоваться преимуществами кода ООП, это означает, что в следующий раз, когда вы измените свой код, вы все равно сможете повторно использовать компоненты. Поскольку программное обеспечение постоянно меняется, на этот раз уже в следующий раз . Таким образом, вы хотите повторно использовать существующий код. Я предполагаю, что одна часть вашего существующего кода - логика вывода. Таким образом, существующая логика вывода должна взаимодействовать с примерными Request и Response выше.

Бьюсь об заклад, вы любите сайты. Вы любите делать так, чтобы они просто работали и выглядели великолепно. Вы создали свой сайт на протяжении многих лет, и даже не все так, как вы хотели бы, вы не хотите его отбрасывать. Поэтому для вашей переписки крайне важно, чтобы вы не уничтожали все, но вы могли сохранить его рабочую форму с этого момента и в будущем (см. Также Сохранение рабочего приложения ; последний пункт списка ).

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

Если сломаешь,

  1. Вы даже заметите?
  2. Вы можете это исправить?

С другой стороны, вы хотите, чтобы код вашего приложения (функции, функциональность) больше не был так тесно привязан к нему , чтобы иметь преимущество в переписывании вашего кода . Как вы хотите переписать свое приложение, давайте посмотрим:

     .---------.                            .-------------.
     | website |  ---> [interface in ] ---> | application |
     | user    |  <--- [interface out] <--- |             |
     `---------´                            `-------------´

Как показывает эта схема, чтобы сделать ваше приложение более независимым от того, как выглядит взаимодействие (может быть веб-сайт, графический интерфейс (смартфон) или система создания билетов), код приложения должен быть заменяемым. Вы не хотите кодировать логику для получения пользовательских игр, например, для каждого типа пользовательского интерфейса в новом коде приложения, но вы сделали это в старом коде приложения.

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

Где-как процедуры регистрации и утери пароля являются частью вашего существующего приложения и продолжают существовать.

Теперь вам нужно соединить старый и новый код.

Так что вы, вероятно, начнете с интерфейса для HTTP-запросов и HTTP-ответа. Представление включается с этим Interface Out . Вы назначаете / передаете все необходимые данные для представления через этот интерфейс, ваше приложение больше не знает представление. Вы не имеете дело с CSS, Javascript или HTML кодом в вашем новом коде приложения. Это просто сахар сверху на выходе. Ваше приложение должно также взаимодействовать через консоль / telnet в виде простого текста или как удаленную службу XMLRPC, конечную точку AJAX - что угодно.

Так что вы, вероятно, можете просто обобщить свой код представления и ввести в него переменные. Написать слой представления можно так же просто, как включить файл PHP. Он работает с переменными, которые доступны в его области видимости. Он может использовать «вспомогательные» функции ( шаблоны макросов ), которые доступны в его области действия. Он может использовать просмотр объектов модели . Можно даже написать свой собственный язык для представления ( язык шаблонов , язык, специфичный для предметной области (DSL)).

Но это возможно только в том случае, если вы создаете интерфейс, который позволяет коду приложения делать это.

Итак, теперь вы удалите HTTP / HTML / CSS / JS из вашего приложения в собственный адаптер. Этот адаптер может сформулировать общую команду, которую можно передать любому приложению через интерфейс в .

Приложение только позаботится о том, чтобы выполнить команду и доставить ответ через interface out .Теперь у вас есть два домена: ваше приложение и веб-сайт.

Вы можете начать создавать эти два новых домена, а затем предлагать интерфейс для вашего старого кода и один для вашего нового кода.

У вас также есть "два" приложения рядом друг с другом.Наконец они связаны (невидимы в своем собственном коде) с вашей базой данных, которая заботится о том, чтобы данные вашего сайта были в порядке.И это то, для чего предназначена база данных.Отделите данные от своего кода, чтобы вы могли со временем изменять свой код.

Также, если вы хотите перекодировать, нарисуйте границу между существующим кодом и новым кодом.

Хорошоудачи!И я надеюсь, что прочитав это, вы увидите несколько вариантов для вашего конкретного случая.Также обратите внимание, что вы не превращаете свои контроллеры в просто еще один фасад для базы данных.Вероятно, вы получаете лучшие преимущества (не знаю вашей конкретной самой большой проблемы), используя легкую HTTP-абстракцию и только слой представления, поскольку ваше приложение предназначено только для веб-сайтов.

Потому что, как вHTTP / PHP:

[Interface In]  Plain Text HTTP request
[Application]   Free to go
[Interface Out] Plain Text HTTP response

Обычно для анализа входных данных и построения выходных данных обычно требуются только некоторые функциональные возможности.

Кроме того, если вы не используете толстые модели, вы получаете быстрый и последовательный доступ к своим данным.Например, если вам не нужно передавать выходные данные сразу (буферизированные, одноблочные), вы можете воспользоваться преимуществами потоковой передачи выходных данных на сервер.

Вы должны решить, какие части важны длярефакторинг для вашего приложения, а не ООП или нет.Как и процедурный, ООП должно быть сделано хорошо.Если сегодня вы сталкиваетесь с проблемами при написании процедурного кода, код ООП может не решить вашу проблему.Это может быть необходимость в написании лучшего процедурного кода.Просто сказать, что нелегко провести рефакторинг приложения, и вы должны сначала определить реальную проблему.

  1. Если вы сломаете это, вы даже заметите?
  2. Если вы сломаете это, можете ли выВы исправляете это?

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

Проверьте свой веб-сайт, так что вы можете сказать, еслиизменение кода здесь или там на самом деле делает хорошо.Иметь возможность отменить любое изменение, если обнаружится, что оно не работает (лучше).

После этого вы можете легко принять решение о новой функции или нет.Пока вам не нужно вводить новые функции, вам не нужно ничего менять в том, как вы пишете функции.А пока вы не сможете планировать новые функции.

Так что лучше подумайте дважды, прежде чем переписывать свое приложение.Как написано, это может убить проект.


См. Также: Как реализовать стиль MVC в моем коде PHP / SQL / HTML / CSS? SO Q & A

7 голосов
/ 31 декабря 2011

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

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

Но у классов есть зоны ответственности, и, как указано выше, класс должен иметь дело со своей зоной ответственности и ничем иным. Рендеринг страницы не является обязанностью любого из классов объектов, упомянутых выше. Вот где приходят классы, которые не представляют сущности вашей системы. Возможно, вам понадобится класс для Page, класс для Session, класс для соединений с базой данных (хотя PHP уже охватил вас с помощью PDO и некоторые другие модули БД, такие как mysqli).

Чтобы отобразить страницу, вы должны использовать экземпляр класса страницы. Вы передадите ему ссылку на зарегистрированный пользовательский объект, ссылки на любые игровые объекты, которые вы хотите, чтобы он отображал, и так далее. Тогда вы бы сделали рендеринг фактического HTML. Класс Page не должен ничего знать о внутренней работе объектов, которые вы передаете ему, кроме как об API, которые эти объекты предоставляют (известные в кругах ООП как протокол объекта, другими словами, их открытые методы и свойства). Класс (очень простой) страницы может выглядеть так:

class Page
{
    private $user = NULL;
    private $games = array ();

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

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

    public function addGame (Game $game)
    {
        $this -> games [] = $game;
    }

    public function getGames ()
    {
        return ($this -> games);
    }

    public function generate ()
    {
        $user = $this -> getUser ();
        $games = $this -> getGames ();

        $pageFile = '/path/to/a/php/script/representing/the/page/markup.php';
        require ($pageFile);
    }

    public function __construct (User $user, array $games)
    {
        $this -> setUser ($user);
        foreach ($games as $game)
        {
            $this -> addGame ($game);
        }
    }
}

Фактический скрипт markup.php, вероятно, будет выглядеть примерно так:

<html>
    <head>
        <title>Games page for <?php echo ($this -> user -> getName ()); ?>
    </head>
    <body>
    <p>Hello, <?php echo ($this -> user -> getName ()), here are your games.</p>
    <?php if (count ($this -> games)) { ?>
    <ul>
        <?php foreach ($this -> games as $game) { ?>
        <li><?php echo ($game -> getName ()); ?>: your best score is <?php echo ($game -> getHighScore ($this -> user)); ?></li>
        <?php } ?>
    </ul>
    <?php } ?>
    </body>
</html>

Как вы могли заметить, если вы используете этот подход, то модули вашего приложения будут иметь тенденцию попадать в одну из трех категорий. Ваши объекты бизнес-логики, такие как «Пользователь» и «Игра», ваша логика отображения, такая как файл markup.php, и третья группа, которая служит формой связующей логики и координации, такой как класс Page.

Хотя в данном конкретном случае это относится к вашему сайту, если вы будете обобщать этот подход дальше, он попадет в шаблон проектирования, известный как MVC, который обозначает Model, View, Controller (ну, на самом деле, он ближе к шаблону, называемому PAC для презентаций, абстракций, контроллеров, но по некоторым причинам он почти всегда называется MVC в сообществе PHP, поэтому сейчас мы просто скажем MVC). Шаблон - это обобщение класса проблем, с которыми программисты сталкиваются на достаточно регулярной основе, что удобно иметь набор готовых решений.

В случае вашего игрового приложения User и Game - это модели, Page - это контроллер, а markup.php - это представление. Если вы подставите в этот код другой скрипт markup.php, вы можете использовать его для представления совершенно одинаковых данных совершенно иным образом, например, в виде файла XML. Вы также можете использовать те же модели с другим контроллером, чтобы заставить их делать разные вещи. Здесь важно помнить, что модели не должны заботиться о том, как они используются, поэтому их можно использовать по-разному, в зависимости от того, чего должен достичь контроллер.

Поскольку MVC является шаблоном, уже существуют наборы инструментов для создания приложений MVC (хотя на самом деле они не являются MVC;)) в PHP. Это так называемые фреймворки. Есть из чего выбирать, например, Symfony, CodeIgnitor, Zend Framework и так далее. Самым популярным фреймворком в наши дни является Zend, хотя я лично не фанат этого. (Я бы сказал, что бета-версии Zend Framework 2 выглядят намного лучше, чем текущая версия фреймворка).

Я надеюсь, что это было полезно для вас. Я знаю, что ООП поначалу может быть пугающим. Это требует, чтобы вы изменили свое мышление как программист, но не волнуйтесь, у него будет достаточно практики.

0 голосов
/ 31 декабря 2011

Пост GordonM хорош для начала.Я бы определенно рекомендовал использовать установленный фреймворк для начала работы - они сделают для вас очень тяжелую работу и помогут вам привыкнуть к ООП в PHP.Лично, если вы используете PHP5.3, я бы порекомендовал Symfomy2, но это чисто личное предпочтение.Я также хотел бы предложить вам получить копию книги "Банды четырех" .Это довольно важное чтение, и хотя оно происходит в основном из среды, не управляемой запросами, многие шаблоны по-прежнему актуальны в PHP.

0 голосов
/ 31 декабря 2011

Все члены в пользовательском классе выглядят так, как будто они там. Важно отделить код GUI от другого кода, я бы поместил displayGames () в некоторый класс интерфейса GUI.

...