Как я могу применить концепции ООП для создания простого, но реального веб-приложения? [закрыто]

25

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

Я не прошу помощи по синтаксису или написанию конкретного кода - я могу найти это сам в документации, а также в поиске на форумах и т. Д. Что мне действительно нужно, так это какое-то руководство и толчок в правильном направлении время от времени. Есть ли опытные программисты, готовые наставлять меня?

В качестве учебного проекта я хотел бы создать простое объявление "веб-приложение". Нечто похожее на Craigslist, но с точки зрения масштабов. Я хотел бы использовать PHP5 и MySQL, потому что я знаком с ними.

Допустим, есть только эти 2 варианта использования:

  1. Размещать что-то для продажи
  2. Просмотр / поиск чего-нибудь купить

Какие "вещи" должны быть объектами? Я могу представить, что каждый предмет может быть объектом, но в какой момент? И почему?

Так, например, пользователь заполняет форму «отправить товар на продажу», должна ли эта форма превратиться в объект, который передается другому объекту, который вставляет значения в базу данных?

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

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

bernk
источник
1
Я нахожусь в одной лодке, я думаю, что понимаю ООП - уже давно, с тех пор, как я попробовал Java, но когда дело доходит до PHP, я бы знал, как сделать такие вещи мгновенно «нормальным» способом, но когда дело доходит до размышлений о том, как это было бы сделано, используя ООП, я теряю желание жить.
martincarlin87
Форма не превращается в объект. Объект является экземпляром класса. Вы могли видеть это так. $ item-> saveItem ($ _ POST ['name'], $ _POST ['description']); редактировать Что действительно помогло мне понять ООП создает простую «гостевую» веб-приложение. Заставьте пользователей входить в систему, публиковать сообщения, редактировать сообщения, удалять сообщения, искать сообщения и т. Д.
@pduersteler хорошая идея, как мне это сделать? Правда, это мой первый вопрос по stackoverflow :)
@ Боно, может быть, приложение гостевой книги, о котором вы упомянули, действительно лучше для начала. Другое, о котором я думал, было очень простое приложение для создания списков, в которое пользователи заходили, создавали / редактировали / удаляли списки, добавляли / редактировали / удаляли элементы в этих списках. Не могли бы вы поделиться своим гостевым приложением с нами / мной?
Я не возражаю, поделившись им, хотя это будет много кода для публикации. Я мог бы поделиться с вами простым примером класса, если хотите. Также я не знаю, насколько хорошо этот код будет работать, потому что, откровенно говоря, это было давно: P Я опубликую его ниже

Ответы:

17

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

Если вы хотите использовать ORM (объектно-реляционное отображение) для взаимодействий с БД, то какая бы среда вы ни использовали или создавали, она, вероятно, будет иметь некоторые поверхностные объекты, представляющие таблицы, которые, вероятно, представляют собой наборы «вещей», но лично мне не нравятся ORM. и я не думаю, что они обязательно представляют идеальные методы ОО, но они популярны для больших веб-приложений.

Кроме того, у вас, вероятно, будут некоторые важные компоненты, которые должен запускать компьютер веб-приложения, такие как одно или несколько подключений к БД (вы можете создать класс, поддерживающий соединение, и вы можете запускать подготовленные запросы из него - PDOотлично подходит сам по себе , но я бы обернул это) и, возможно, система шаблонов для ваших взглядов. Вы можете также захотеть, чтобы ваши контроллеры были объектами PHP. Если у вас есть форма для заполнения, у вас может быть объект, который поддерживает значения формы для P / R / G, токен CSRF-защиты и может выполнять проверку его входных данных.

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

Мой последний совет: составление наследства - это путь.

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

Вот как вы можете использовать ООП для покупки и продажи своих питомцев, та же методика может быть использована для продажи автомобилей или самолетов; p

<?php
// define a superclass .. no instances will be made of 'animal' itself,
// but it is useful to define common characteristics and behaviours
// (ie: properties and methods) of all our classes of animals
class Animal {

    // this constructor function is called whenever a new instance
    // of the Animal class is created (or any class that inherits from Animal)
    function Animal ($colour) {

        // install the argument as an attribute of any instances of Animal
        $this->colour = $colour;
    }

    // this method will be available to all classes that inherit from Animal
    function report () {
        return "This ".$this->colour." ".get_class($this)." has ".$this->legs." legs.<br />";
    }
}

// this class inherits from Animal
class Cat extends Animal {

    // set the legs attribute
    public $legs = 4;

    // create a method that can be called from any instances of Cat
    function make_noise () {
        echo "MEOW!<br />";
    }
}

// this class inherits from Cat, and from Animal
class Panther extends Cat {

    // specifies the colour attribute
    public $colour = "black";

    // overwrites the constructor function that would otherwise be
    // inherited from Animal, with a blank constructor.
    function Panther () {}

    // overwrites the method inherited from Cat
    function make_noise () {
        echo "ROARRRR!<br />";
    }
}

// this class inherits from Animal
class Snake extends Animal {
    public $legs = 0;
}

// this class is unrelated to the others
class PetShop {

    // set up an array to store the pets that the shop will stock
    public $pets = array ();

    // set up a variable to store the total cash in the pet shop
    public $cash;

    // this method creates a new object and adds it to the pets array
    function add_pet ($petclass, $price, $colour) {

        // set up a variable containing the number of elements in the pets array
        $n_pets = count($this->pets);

        // add to the pets array, a new instance of the class specified as
        // the first argument in this method, using the last argument as the
        // colour argument that is passed to the specified class's constructor
        $this->pets[$n_pets] = new $petclass($colour);

        // add a 'price' attribute to the pet object
        $this->pets[$n_pets]->price = $price;
    }

    // this method removes the specified pet from the array and adds the price
    // to the pet shop's cash variable
    function sell_pet ($n) {

        // add pet's price to the cash total
        $this->cash += $this->pets[$n]->price;

        // remove the pet object from the array
        array_splice($this->pets, $n, 1);

        // give a message about the sale
        echo "SALE: Pet no. ".$n." sold. Total cash is now \$".$this->cash.".<br /><br />";
    }

    // this method reports on the pet shop's stock
    function show_pets () {

        // show the number of pets available
        echo "<B>Shop stock:</B><br />We have ".count($this->pets)." pets for sale.";
        echo "<br /><br />";

        // iterate through the pets array and show information about each one
        for ($i = 0; $i < count($this->pets); $i++) {
            echo "<B>Pet No. ".$i.": </b>".$this->pets[$i]->report();
            echo "Price: \$".$this->pets[$i]->price."<br />";
        }
        echo "<br />";
    }
}

// instantiate a new PetShop object
$shop = new PetShop ();

// add three pets to the shop
$shop->add_pet(cat, 20, "tabby");
$shop->add_pet(snake, 40, "brown");
$shop->add_pet(snake, 60, "black");

// show the pet's stock
$shop->show_pets();

// sell the first pet in the stock
$shop->sell_pet(0);

// show the pet's stock after the sale
$shop->show_pets();
?>
Лоуренс Чероне
источник
28
Если я увижу еще один пример с автомобилями или животными, я его потеряю
Нил Макгиган
5

По запросу ОП я поделюсь кодом моей гостевой книги.
Класс сообщения:

<?php 
Class message
{
    private $db;
    private $messageID;
    private $message;
    private $name;
    private $mail;

    public function setmessageID($messageID)
    {
        $this->messageID = $messageID;
    }

    public function getmessageID()
    {
        return $this->messageID;
    }

    public function setmessage($message)
    {
        $this->message = $message;
    }

    public function getmessage()
    {
        return $this->message;
    }

    public function setname($name)
    {
        $this->name = $name;
    }

    public function getname()
    {
        return $this->name;
    }

    public function setMail($mail)
    {
        $this->mail = $mail;
    }

    public function getMail()
    {
        return $this->mail;
    }
}

Класс объекта доступа к данным сообщения:

<?php 
class messageDAO
{
    private $db;
    private $aantalMessages;
    private $messages;
    private $message;

    //bij laden roept hij automatisch Db class aan (en de daarbij gezeten functies)
    public function __construct(Db $db)
    {
        $this->db = $db;
    }

    public function getMessages()
    {
        return $this->messages;
    }

    public function getAantalMessages()
    {
        return $this->aantalMessages;
    }

    //Function to retrieve messages
    public function findMessages($args)
    {       
        $dbh = $this->db->DBH();

        //$offset for pagination
        $offset = ($args['currentPage'] - 1) * $args['itemsPerPage'];

        $sth = $dbh->prepare("SELECT    SQL_CALC_FOUND_ROWS
                                                    messageen.messageID, 
                                                    messageen.message, 
                                                    messageen.name, 
                                                    messageen.mail
                                            FROM    `messageen` 
                                            ORDER BY messageen.datumToegevoegd DESC 
                                            LIMIT   ?, ?");
        $sth->bindParam(1, $offset, PDO::PARAM_INT);
        $sth->bindParam(2, $args['itemsPerPage'], PDO::PARAM_INT);
        $sth->execute();
        $sth->setFetchMode(PDO::FETCH_ASSOC);

        $messages = array();

        while($row = $sth->fetch())
        {
            $message = new message();
            $message->setMessageID(htmlentities(strip_tags($row['messageID'])));
            $message->setSessage(htmlentities(strip_tags($row['message'])));
            $message->setName(htmlentities(strip_tags($row['name'])));
            $message->setMail(htmlentities(strip_tags($row['mail'])));  
            $messages[] = $message; 
        }

        $sth = $dbh->prepare("SELECT FOUND_ROWS() as numberOfMessages");
        $sth->execute();
        $sth->setFetchMode(PDO::FETCH_ASSOC);
        $this->numberOfMessages = $sth->fetch();

        return $messages;
    }

    public function setMessageToEdit($args)
    {   
        $sth = $this->db->DBH()->prepare("SELECT    messages.message
                                            FROM    `messages`
                                            WHERE   messages.messageID = ?");
        $sth->bindParam(1, $args['messageID']);
        $sth->execute();
        $sth->setFetchMode(PDO::FETCH_ASSOC);
        //return the retrieved message
        while($row = $sth->fetch())
        {
            $message = new message();
            $message->setMessage(htmlentities(strip_tags($row['message'])));
            $message->setMessageID(intval($args['messageID']));
        }

        return $message;
    }

    //functie om messageen aan te passen
    public function save(message $message)
    {   
        //insert part
        //if(isset($message->getname()) && isset($message->getmessage()) && isset($message->getMail()))
        //{
            $sth = $this->db->DBH()->prepare("INSERT INTO   `messages`
                                                    SET     messages.name = ?,
                                                            messages.mail = ?,
                                                            messages.message = ?,
                                                            messages.dateAdded = NOW()");
            $sth->bindParam(1, $message->getName());
            $sth->bindParam(2, $message->getMail());
            $sth->bindParam(3, $message->getMessage());
            $sth->execute();
        //}

        //update part       
        /*if(isset($message->getmessageID()) && isset($message->getmessage()))
        {
            $sth = $this->db->DBH()->prepare("UPDATE    `messageen`
                                                SET     messageen.message = ? 
                                                WHERE   messageen.messageID = ?
                                                LIMIT   1");
            $sth->bindParam(1, $message->getmessage());
            $sth->bindParam(2, $message->getmessageID());
            $sth->execute();
        }*/
    }
}

index.php

<?php
//include file loader.php
include("includes/loader.php");

$guestbook = new guestbook($db);
$user = new user($db);
$messageDAO = new messageDAO($db);

//Make a array named error
$error = array();

//Get action (login/setmessage/editmessage/deletemessage)
if(isset($_GET['action']))
{   
    switch ($_GET['action'])
    {   
        //if login submit is pressed
        case 'login':
            //Check if filled
            if(isset($_POST['username']) && isset($_POST['username']))
            {
                $error['usernameEmpty'] = (bool) !strlen(trim($_POST['username']));
                $error['passwordEmpty'] = (bool) !strlen(trim($_POST['password']));
            }

            if(in_array(1, $error))
            {
                //Assign $error to smarty
                $smarty->assign('error', $error);
            }

            else
            {
                if(isset($_POST['username']) && isset($_POST['username']))
                {
                    $user->setLoggedIn(array('username'=>$_POST['username'],
                    'password'=>$_POST['password']));

                    if($user->getLoggedIn() != true)
                    {                   
                        $smarty->assign('loggedInError', $user->getLoggedIn());
                    }
                }
            }
            break;

        //Als if "place message" is pressed
        case 'placemessage':
            //if user is not logged in
            if($user->getLoggedIn() != true)
            {
                //Controleren of message-velden wel zijn ingevuld
                $error['nameEmpty'] = (bool) !strlen(trim(htmlentities(strip_tags($_POST['messagename']))));
                $error['mailEmpty'] = (bool) !strlen(trim(htmlentities(strip_tags($_POST['messageMail']))));
                $error['messageEmpty'] = (bool) !strlen(trim(htmlentities(strip_tags(str_replace('place message...','', $_POST['messageInput'])))));

                if($error['mailEmpty'] != 1)
                {
                    $error['mailInvalid'] = !filter_input((INPUT_POST), 'messageMail', FILTER_VALIDATE_EMAIL);
                }

                if(in_array(1, $error))
                {
                    $smarty->assign('error', $error);
                }

                else
                {
                    $message = new message();

                    $message->setname($_POST['messagename']);
                    $message->setMail($_POST['messageMail']);
                    $message->setmessage($_POST['messageInput']);

                    dump($message);

                    //place message             
                    $messageDAO->save($message);
                }
            }

            //if user is logged in
            else 
            {
                //is message filled?
                $error['messageEmpty'] = (bool) !strlen(trim(htmlentities(strip_tags(str_replace('place hier uw message...','', $_POST['messageInput'])))));

                if($error['messageEmpty'] != 1)
                {   
                    $user->setUser();

                    $guestbook->placemessage(array('name'=>$user->getLoggedInUsername(), 
                    'mail'=>$user->getLoggedInUserMail(),
                    'messageInput'=>$_POST['messageInput']));
                }

                else 
                {
                    $smarty->assign('error', $error);
                }
            }
            break;

        case 'deletemessage':
            $user->setUser();

            if($user->getLoggedInUserAdmin() == 1)
            {
                if(isset($_GET['messageID']) && is_numeric($_GET['messageID']) && isset($_GET['key']))
                {
                    $guestbook->setURLKey($_GET['messageID']);

                    if($guestbook->getURLKey() == $_GET['key'])
                    {                   
                        $guestbook->verwijdermessage(array('messageID'=>$_GET['messageID']));
                    }
                }
            }
            die(header("location: /index.php"));
            break;
    }
}

if(isset($_GET['pagina']) && is_numeric($_GET['pagina']))
{

    $currentpage = $_GET['pagina'];
}

else
{
    //$currentpage is 1
    $currentpage = 1;
}

$user->setUser();

//assign var to smarty
$smarty->assign('messages', $messageDAO->findmessages(array('currentpage'=>$currentpage, 'itemsPerPagina'=>10)));
$smarty->assign('user', $user);

//Pagination

$numbermessages = $messageDAO->getnumbermessages();


$totalpages = ceil($numbermessages['numbermessages'] / 10);


if($currentpage < 1)
{
    //$currentpage is 1
    $currentpage = 1;
}


if($currentpage > $totalpages)
{

    $currentpage = $totalpages;
}

$smarty->assign('numbermessages', $messageDAO->getnumbermessages());
$smarty->assign('guestbook', $guestbook);
$smarty->assign('currentpage', $currentpage);
$smarty->assign('totalpages', $totalpages);

//display index.tpl
$smarty->display('index.tpl');

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

Боно
источник
3

Как уже упоминалось в Explosion Pills, в сложном приложении большинство объектов относятся к компонентам приложения (например, к пулам соединений с базами данных, командам, структурам данных, таким как хэш-карты), а не к объектам реального мира (таким как посадочный талон, счет-фактура или файл mp3. ). Есть много хороших книг по шаблонам проектирования, которые показывают вам, как люди решили много повторяющихся проблем в этой области. Книга GOF, как известно, тщательна, но очень суха, шаблоны проектирования Head First могут быть более доступными.

С точки зрения анализа реального мира и дизайна. Часто полезно думать с точки зрения существительных и глаголов. Например, библиотека видеопроката (сейчас они устарели?) Может иметь следующие вещи / существительные:

  • видео
  • заемщик

С точки зрения глаголов:

  • Заемщик может снять видео на длительный срок
  • Заемщик может вернуть видео в магазин и т. Д.

Затем их можно превратить в классы с операциями (я давно не делал PHP, поэтому буду избегать этого):

class Borrower
{
  public void borrow(Video video, int daysToBorrow)
  {
     ...
  }

  public void returnVideo(Video video, boolean calculateFine)
  {
     ...
  }
}

Все это требует много практики и игры. Лучшее, что можно сделать, это застрять и извлечь уроки из неудачных проектов. По моему мнению, OO - это то, что вы можете продолжать изучать и развивать в течение своей жизни (это нелегко и нет идеальных решений для чего-либо). Хороший дизайн часто повторяется, поэтому попробуйте несколько разных идей для своего веб-приложения «Список Крейга».

mward
источник
1

Лучше всего найти способ сосредоточиться на ядре вашего приложения - «post», «user», «post :: FindByName ()», «user-> Validate ()» и т. Д., И не беспокоиться слишком много о сантехнике - как склеивать посты с таблицами базы данных, как поддерживать отображение поста согласованным между разными поисками и как склеивать форму «вводить пост» с записью базы данных.

К счастью, есть много платформ, которые делают это для вас; доминирующей парадигмой в веб-приложениях OO является «Model-View-Controller», также известный как MVC ; в PHP есть несколько готовых MVC-фреймворков, которые вы можете использовать.

Хотя это расширяет ваши потребности в обучении - теперь вы должны изучать как MVC, так и OO - это означает, что ваши усилия в области OO в основном ограничены уровнем «Model», который представляет вашу бизнес-область; вот где ОО является наиболее естественным и выразительным. Большинство инфраструктур MVC позволяют вам определять свой «модельный» слой, а затем автоматически создавать веб-сайт вокруг него, используя технику, известную как скаффолдинг - таким образом, вы получаете быстрый способ экспериментировать с различными реализациями для вашей доменной модели, без приходится отрывать всю сантехнику.

Невилл Кайт
источник