Come posso applicare i concetti OOP per creare un'app Web semplice ma reale? [chiuso]


25

Sto provando da molto tempo a avvolgere la mia testa intorno a OOP. Vedo i suoi vantaggi. Ho letto molti, molti tutorial e guardato una quantità uguale di video sull'argomento. Ottengo esempi di animali / gatti / cani, ottengo esempi di automobili / unità. Ciò con cui sto lottando è come applicare questi concetti in un'applicazione del mondo reale. Quindi, ho deciso di costruirne uno usando OOP.

Non sto chiedendo aiuto con la sintassi o scrivendo un codice specifico - posso trovarlo nella documentazione e cercare nei forum ecc. Ciò di cui ho davvero bisogno è una guida e una spinta nella giusta direzione di tanto in tanto. Ci sono programmatori esperti disposti a seguirmi?

Come mio progetto di apprendimento, vorrei creare una semplice "web app" di annunci. Qualcosa di simile a Craigslist ma molto annacquato in termini di portata. Vorrei usare PHP5 e MySQL, perché ne ho familiarità.

Diciamo che ci sono solo questi 2 casi d'uso:

  1. Pubblicare qualcosa in vendita
  2. Navigazione / ricerca di qualcosa da acquistare

Quali "cose" dovrebbero essere oggetti? Posso immaginare che ogni oggetto possa essere un oggetto, ma a che punto? E perché?

Ad esempio, l'utente compila il modulo "Posta in vendita", dovrebbe essere trasformato in un oggetto che viene passato a un altro oggetto che inserisce i valori in un database?

Che dire quando un altro utente sta navigando e richiede di vedere tutti gli elementi della categoria C? Ha senso che ogni volta che l'app deve connettersi al suo database crea un oggetto database e quindi ottiene un mucchio di oggetti oggetto e li visualizza sulla pagina? ... scrivere questo sicuramente mi fa capire quanto sono ancora all'oscuro di OOP. Per favore, aiutatemi a risolverlo.

Se secondo te questo non è un buon progetto con cui iniziare a guadare OOP, sentiti libero di suggerire un'altra idea!


1
Sono nella stessa barca, penso di aver capito OOP - è passato un po 'di tempo da quando ho provato Java, ma quando si tratta di PHP saprei fare cose come questa all'istante in modo "normale" ma quando si tratta di pensare a come sarebbe fatto usando OOP perdo la voglia di vivere.
martincarlin87,

Il modulo non viene trasformato in un oggetto. Un oggetto è un'istanza di una classe. Potresti vederlo così. $ item-> saveItem ($ _ POST ['name'], $ _POST ['description']); modifica Ciò che mi ha davvero aiutato a capire OOP è la creazione di una semplice web-app "guestbook". Permetti agli utenti di accedere, pubblicare messaggi, modificare messaggi, eliminare messaggi e cercare messaggi ecc.

@pduersteler buona idea, come posso fare per farlo? Certo, questa è la mia prima domanda su StackOverflow :)

@Bono forse un'app del libro degli ospiti come hai menzionato è davvero un posto migliore per iniziare. L'altra a cui stavo pensando era un'app di elenco molto semplice in cui gli utenti accedono, creano / modificano / eliminano elenchi, aggiungono / modificano / eliminano elementi in quegli elenchi. Ti dispiacerebbe condividere la tua app per il libro degli ospiti con noi / me?

Non mi dispiacerebbe condividerlo, anche se sarebbe un sacco di codice da pubblicare. Potrei condividere una semplice lezione di esempio con te se vuoi. Inoltre non so quanto funzionerà bene questo codice, perché francamente è passato un po 'di tempo: P Lo posterò di seguito

Risposte:


17

Onestamente penso che il consiglio qui sia stato terribile per i nuovi studenti OO finora. Non è una buona idea iniziare immediatamente a pensare agli oggetti come rappresentazioni di un'istanza specifica di una "cosa" definita da una classe. È meglio pensarli come componenti compartimentati di una macchina che hanno una certa interazione tra loro, ma non gli interni degli altri. Ognuno di questi componenti mantiene lo stato

Se vuoi usare un ORM (object-relational-mapping) per le interazioni di DB, qualunque framework tu usi o crei probabilmente avrà degli oggetti superficiali che rappresentano tabelle, che sono probabilmente raccolte di "cose", ma non mi piacciono personalmente gli ORM e non penso che rappresentino necessariamente pratiche OO ideali, ma sono popolari per le app Web di grandi dimensioni.

Oltre a ciò, avrai probabilmente alcuni componenti importanti che la macchina dell'app web deve eseguire come una o più connessioni DB (puoi creare una classe che mantiene una connessione e puoi eseguire query preparate da - PDOè eccezionale da solo , ma lo avvolgo) e forse un sistema di template per le tue visualizzazioni. Puoi anche voler che i tuoi controller siano oggetti PHP. Se hai un modulo da compilare, potresti avere un oggetto che mantiene i valori del modulo per P / R / G, un token di protezione CSRF e può eseguire la convalida sui suoi input.

Non dovresti provare a cercare "cose" da trasformare in oggetti quando costruisci il tuo design di app web e il grafico degli oggetti. Invece, dovresti pensare ai componenti logici che si uniscono per crearlo. Non penso che dovresti provare a forzare questo, e dovrebbe venire abbastanza naturalmente, ma è molto difficile farlo correttamente e finirai sicuramente per cambiare alcune decisioni di progettazione lungo la strada.

Il mio ultimo consiglio è questo: la composizione oltre l'eredità è la strada da percorrere.


Una regola empirica che ho, specialmente per i linguaggi dinamici, è quella di provare a creare classi solo se voglio trarre vantaggio dal polimorfismo (cioè se tali classi implementeranno versioni diverse dello stesso metodo e la logica dipenderà da quella in qualche modo). Altrimenti, cerco di sbagliare sulla scrittura in uno stile più "procedurale", al fine di renderlo semplice.
hugomg,

9

Ecco come puoi usare OOP per comprare e vendere i tuoi animali domestici, la stessa metodologia potrebbe essere usata per vendere auto o aerei; 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
Se vedo un altro esempio di oop con macchine o animali, lo perderò
Neil McGuigan,

5

Su richiesta di OP condividerò il mio codice del libro degli ospiti.
Classe del messaggio:

<?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;
    }
}

Classe oggetto di accesso ai dati dei messaggi:

<?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');

Ho rinominato alcune delle variabili e delle funzioni per dare un senso a te (tradotto dall'olandese in inglese: P), quindi potresti trovare delle frasi strane a volte perché ho appena fatto una sostituzione rapida, ecc. Divertiti. Anche questo non è l'intero codice perché ciò comporterebbe la pubblicazione di 20 file di codice: P


3

Come indicato da Explosion Pills, in un'applicazione complessa la maggior parte degli oggetti si riferisce a componenti dell'applicazione (ad es. Pool di connessione al database, comandi, strutture di dati come hashmaps) piuttosto che entità del mondo reale (come una carta d'imbarco, una fattura o un file mp3 ). Ci sono molti buoni libri sui modelli di design che mostrano come le persone hanno risolto molti problemi ricorrenti in questo settore. Il libro GOF, come è noto, è accurato ma molto secco, i modelli Head First Design potrebbero essere più accessibili.

In termini di analisi e progettazione del mondo reale. Spesso è utile pensare in termini di nomi e verbi. Ad esempio, una libreria di prestiti video (sono obsoleti adesso?) Può contenere questi elementi / nomi:

  • video
  • mutuatario

In termini di verbi:

  • Un mutuatario può realizzare un video per un certo periodo di tempo
  • Un mutuatario può restituire un video al negozio ecc.

Questi possono quindi essere trasformati in classi con operazioni (è molto tempo che non faccio PHP, quindi lo eviterò):

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

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

Tutto richiede molta pratica e gioco. La cosa migliore da fare è rimanere bloccati e imparare dai progetti falliti. Secondo me OO è qualcosa che puoi continuare a imparare e sviluppare nel corso della tua vita (non è facile e non ci sono soluzioni perfette a nulla). Un buon design è spesso iterativo, quindi aspettati di provare alcune idee diverse per la tua webapp "Craig's List".


1

La cosa migliore da fare è trovare un modo per concentrarsi sul nucleo dell'applicazione: "post", "user", "post :: FindByName ()", "user-> Validate ()" ecc., E non preoccuparti troppo sull'impianto idraulico - come incollare i post alle tabelle del database, come mantenere la visualizzazione di un post coerente tra ricerche diverse e come incollare il modulo "inserisci post" su un record del database.

Fortunatamente, ci sono molti framework che fanno questo per te; il paradigma dominante nelle applicazioni web OO è "Model-View-Controller", noto anche come MVC ; in PHP, ci sono una serie di framework MVC pronti all'uso che puoi usare.

Mentre questo espande la tua necessità di apprendere - ora devi conoscere MVC e OO - ciò significa che i tuoi sforzi OO sono per lo più vincolati al livello "Modello", che rappresenta il tuo dominio aziendale; ecco dove OO è più naturale ed espressivo. La maggior parte dei framework MVC ti consente di definire il tuo livello "modello", e quindi di creare automagicamente un sito web attorno a quello usando una tecnica nota come ponteggio - in questo modo, puoi ottenere un modo rapido di sperimentare diverse implementazioni per il tuo modello di dominio, senza dover staccare tutto l'impianto idraulico.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.