Wie kann ich OOP-Konzepte anwenden, um eine einfache, aber reale Web-App zu erstellen? [geschlossen]


25

Ich habe jetzt seit langer Zeit versucht, meinen Kopf um OOP zu wickeln. Ich sehe seine Vorteile. Ich habe viele, viele Tutorials gelesen und mir zu diesem Thema gleich viele Videos angesehen. Ich bekomme die Tier- / Katzen- / Hundebeispiele, ich bekomme die Auto- / Fahrtbeispiele. Ich habe Probleme damit, diese Konzepte in einer realen Anwendung anzuwenden. Also habe ich mich vorgenommen, eine mit OOP zu erstellen.

Ich bitte nicht um Hilfe bei der Syntax oder beim Schreiben von spezifischem Code - ich finde das selbst in der Dokumentation und beim Durchsuchen von Foren usw. Was ich wirklich brauche, ist eine Anleitung und hin und wieder ein Vorstoß in die richtige Richtung. Gibt es erfahrene Programmierer, die bereit sind, mich zu betreuen?

Als mein Lernprojekt möchte ich eine einfache Kleinanzeigen "Web App" erstellen. Ähnlich wie bei Craigslist, aber vom Umfang her verwässert. Ich möchte PHP5 und MySQL verwenden, weil ich mit ihnen vertraut bin.

Angenommen, es gibt nur diese zwei Anwendungsfälle:

  1. Etwas zum Verkauf anbieten
  2. Stöbern / Suchen nach etwas zum Kaufen

Welche "Dinge" sollen Gegenstände sein? Ich kann mir vorstellen, dass jeder Gegenstand ein Objekt sein könnte, aber an welchem ​​Punkt? Und warum?

Wenn der Benutzer beispielsweise das Formular "Artikel zum Verkauf bereitstellen" ausfüllt, wird dieses Formular dann in ein Objekt umgewandelt, das an ein anderes Objekt übergeben wird, das die Werte in eine Datenbank einfügt.

Was ist, wenn ein anderer Benutzer gerade im Internet surft und alle Artikel der Kategorie C anfordert? Ist es sinnvoll, dass die App immer dann, wenn sie eine Verbindung zu ihrer Datenbank herstellen muss, ein Datenbankobjekt erstellt, eine Reihe von Elementobjekten abruft und diese auf der Seite anzeigt? … Wenn ich das aufschreibe, wird mir klar, wie ahnungslos ich immer noch über OOP bin. Bitte helfen Sie mir, das zu beheben.

Wenn Sie der Meinung sind, dass dies kein gutes Projekt ist, um sich mit OOP vertraut zu machen, können Sie gerne eine andere Idee vorschlagen!


1
Ich bin im selben Boot, ich glaube ich verstehe OOP - es ist schon eine Weile her, seit ich Java ausprobiert habe, aber wenn es um PHP geht, würde ich sofort wissen, wie man so etwas auf die "normale" Weise macht, aber wenn man darüber nachdenkt, wie Es würde mit OOP gemacht werden. Ich verliere den Willen zu leben.
Martincarlin87

Das Formular wird nicht in ein Objekt umgewandelt. Ein Objekt ist eine Instanz einer Klasse. Sie könnten es so sehen. $ item-> saveItem ($ _POST ['name'], $ _POST ['description']); edit Was mir wirklich geholfen hat, OOP herauszufinden, ist die Erstellung einer einfachen "Gästebuch" Web-App. Veranlassen Sie Benutzer, sich anzumelden, Nachrichten zu posten, Nachrichten zu bearbeiten, Nachrichten zu löschen und nach Nachrichten zu suchen usw.

@pduersteler gute idee, wie mache ich das? Zugegeben, das ist meine erste Frage zu stackoverflow :)

@Bono Vielleicht ist eine Gästebuch-App wie du sie erwähnt hast in der Tat ein besserer Startpunkt. Die andere, über die ich nachdachte, war eine sehr einfache Listen-App, bei der sich Benutzer anmelden, Listen erstellen / bearbeiten / löschen, Elemente in diesen Listen hinzufügen / bearbeiten / löschen. Würde es Ihnen etwas ausmachen, Ihre Gästebuch-App mit uns / mir zu teilen?

Es würde mir nichts ausmachen, es zu teilen, obwohl es eine Unmenge von Code zum Posten wäre. Ich könnte Ihnen eine einfache Beispielstunde geben, wenn Sie möchten. Ich weiß auch nicht, wie gut dieser Code funktionieren wird, denn ehrlich gesagt ist es schon eine Weile her: P Ich werde es unten posten

Antworten:


17

Ich denke ehrlich, dass der Ratschlag hier für neue OO-Lernende bisher schrecklich war. Es ist keine gute Idee, Objekte sofort als Repräsentationen einer bestimmten Instanz eines "Dings" zu betrachten, das von einer Klasse definiert wird. Es ist besser, sie als unterteilte Komponenten einer Maschine zu betrachten, die eine gewisse Interaktion miteinander haben, aber nicht die Interna der anderen. Jede dieser Komponenten behält den Status bei

Wenn Sie ein ORM (Object-Relational-Mapping) für DB-Interaktionen verwenden möchten, enthält jedes Framework, das Sie verwenden oder erstellen, möglicherweise einige flache Objekte, die Tabellen darstellen, bei denen es sich wahrscheinlich um Sammlungen von "Dingen" handelt. Ich persönlich mag ORMs jedoch nicht und ich denke nicht, dass sie unbedingt ideale OO-Praktiken darstellen, aber sie sind beliebt für große Web-Apps.

Außerdem werden Sie wahrscheinlich einige wichtige Komponenten haben, die der Web-App-Computer ausführen muss, wie z. B. eine oder mehrere DB-Verbindungen (Sie können eine Klasse erstellen, die eine Verbindung aufrechterhält, und Sie können vorbereitete Abfragen von ausführen - PDOist großartig für sich , aber ich würde es einpacken), und vielleicht ein Template-System für Ihre Ansichten. Möglicherweise möchten Sie, dass Ihre Controller auch PHP-Objekte sind. Wenn Sie ein Formular ausfüllen müssen, verfügen Sie möglicherweise über ein Objekt, das Formularwerte für P / R / G, ein CSRF-Schutztoken, verwaltet und dessen Eingaben validieren kann.

Sie sollten nicht versuchen, nach "Dingen" zu suchen, die sich in Objekte verwandeln, wenn Sie Ihr Web-App-Design und Ihr Objektdiagramm erstellen. Stattdessen sollten Sie über die logischen Komponenten nachdenken, die zusammenkommen, um es zu erstellen. Ich denke nicht, dass Sie versuchen sollten, dies zu erzwingen, und es sollte ziemlich natürlich kommen, aber es ist sehr schwierig, es richtig zu machen, und Sie werden definitiv einige Designentscheidungen auf dem Weg ändern müssen.

Mein letzter Rat lautet: Komposition über Vererbung ist der richtige Weg.


Eine Faustregel, die ich speziell für dynamische Sprachen habe, ist, zu versuchen, Klassen nur dann zu erstellen, wenn ich den Polymorphismus nutzen möchte (dh wenn diese Klassen verschiedene Versionen derselben Methode implementieren und die Logik davon abhängt) irgendwie). Ansonsten versuche ich mich beim Schreiben in einem "prozeduralen" Stil zu irren, um es einfach zu halten.
Hugomg

9

Hier erfahren Sie, wie Sie mit OOP Ihre Haustiere kaufen und verkaufen können. Dieselbe Methode kann auch für den Verkauf von Autos oder Flugzeugen verwendet werden

<?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
Wenn ich noch ein Beispiel mit Autos oder Tieren sehe, werde ich es verlieren
Neil McGuigan

5

Auf Wunsch von OP teile ich meinen Gästebuchcode mit.
Nachrichtenklasse:

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

Nachrichtendatenzugriffsobjektklasse:

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

Ich habe einige der Variablen und Funktionen umbenannt, um Ihnen einen Sinn zu geben (übersetzt von Niederländisch nach Englisch: P), damit Sie manchmal seltsame Empfindungen finden, weil ich sie nur schnell ersetzt habe usw. Viel Spaß damit. Dies ist auch nicht der gesamte Code, da ich dann etwa 20 Dateien mit folgendem Code posten würde: P


3

Wie von Explosion Pills erwähnt, beziehen sich in einer komplexen Anwendung die meisten Objekte auf Anwendungskomponenten (z. B. Datenbankverbindungspools, Befehle, Datenstrukturen wie Hashmaps) und nicht auf reale Entitäten (z. B. Bordkarte, Rechnung oder MP3-Datei) ). Es gibt viele gute Bücher zu Designmustern, die Ihnen zeigen, wie Menschen viele wiederkehrende Probleme in diesem Bereich gelöst haben. Das so genannte GOF-Buch ist gründlich, aber sehr trocken. Head First Design Patterns sind möglicherweise besser zugänglich.

In Bezug auf Analyse und Design der realen Welt. Es ist oft hilfreich, in Substantiven und Verben zu denken. Beispielsweise kann eine Videokreditbibliothek (sind diese jetzt veraltet?) Die folgenden Dinge / Substantive enthalten:

  • Video
  • Kreditnehmer

In Bezug auf Verben:

  • Ein Kreditnehmer kann ein Video über einen längeren Zeitraum hinweg aufnehmen
  • Ein Leihnehmer kann ein Video in den Laden usw. zurückgeben.

Diese können dann in Klassen mit Operationen umgewandelt werden (es ist lange her, dass ich PHP gemacht habe, also werde ich es vermeiden):

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

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

Es braucht viel Übung und Spielerei. Das Beste, was Sie tun können, ist, sich auf die fehlgeschlagenen Entwürfe einzulassen und daraus zu lernen. Meiner Meinung nach ist OO etwas, das Sie über Ihr Leben hinweg weiter lernen und entwickeln können (es ist nicht einfach und es gibt keine perfekten Lösungen für irgendetwas). Gutes Design ist oft iterativ. Probieren Sie ein paar verschiedene Ideen für Ihre "Craig's List" -Webapp aus.


1

Das Beste, was Sie tun können, ist, sich auf den Kern Ihrer Anwendung zu konzentrieren - "post", "user", "post :: FindByName ()", "user-> Validate ()" usw., und sich keine Sorgen zu machen zu viel über die Installation - wie man Beiträge in Datenbanktabellen einfügt, wie man die Anzeige für einen Beitrag zwischen verschiedenen Suchvorgängen konsistent hält und wie man das Formular "Beitrag eingeben" in einen Datenbankdatensatz einfügt.

Glücklicherweise gibt es viele Frameworks, die dies für Sie tun. Das vorherrschende Paradigma in OO-Webanwendungen ist "Model-View-Controller", auch als MVC bekannt . In PHP gibt es eine Reihe von Standard-MVC-Frameworks, die Sie verwenden können.

Während dies Ihr Lernbedürfnis erweitert - Sie müssen jetzt sowohl MVC als auch OO kennenlernen -, bedeutet dies, dass sich Ihre OO-Bemühungen größtenteils auf die Ebene "Modell" beschränken, die Ihre Geschäftsdomäne darstellt. Hier ist OO am natürlichsten und ausdrucksvollsten. Mit den meisten MVC-Frameworks können Sie Ihre "Modell" -Schicht definieren und anschließend mithilfe einer als "Scaffolding" bezeichneten Technik automatisch eine Website um diese herum erstellen. Auf diese Weise erhalten Sie eine schnelle Möglichkeit, mit verschiedenen Implementierungen für Ihr Domain-Modell zu experimentieren, ohne die Klempnerarbeiten abwickeln zu müssen.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.