web-dev-qa-db-fra.com

Comment puis-je appliquer les concepts OOP) à la création d'une application Web simple mais réelle?

Cela fait longtemps que j'essaie d'enrouler ma tête autour de la POO. Je vois ses avantages. J'ai lu de très nombreux tutoriels et regardé un nombre égal de vidéos sur le sujet. Je reçois les exemples animaux/chats/chiens, je reçois les exemples voiture/voiture. Ce qui me pose problème, c'est comment appliquer ces concepts dans une application réelle. J'ai donc décidé d'en créer un à l'aide de la POO.

Je ne demande pas d'aide pour la syntaxe ou l'écriture de code spécifique - je peux le trouver moi-même dans la documentation et en cherchant dans les forums, etc. Ce dont j'ai vraiment besoin, c'est de conseils et d'un Push dans la bonne direction de temps en temps. Y a-t-il des programmeurs chevronnés prêts à me conseiller?

Dans le cadre de mon projet d'apprentissage, je voudrais créer une simple "application web" pour les petites annonces. Quelque chose de similaire à Craigslist, mais de manière diluée en termes de portée. Je voudrais utiliser PHP5 et MySQL, car je les connais bien.

Disons qu'il n'y a que ces 2 cas d'utilisation:

  1. Publier quelque chose à vendre
  2. Parcourir/rechercher quelque chose à acheter

Quelles "choses" devraient être des objets? Je peux imaginer que chaque élément pourrait être un objet, mais à quel moment? Et pourquoi?

Ainsi, par exemple, l'utilisateur remplit le formulaire "publier l'article à vendre", ce formulaire doit-il être transformé en un objet qui est transmis à un autre objet qui insère les valeurs dans une base de données?

Qu'en est-il lorsqu'un autre utilisateur navigue et demande à voir tous les éléments de la catégorie C? Est-il logique que chaque fois que l'application doit se connecter à sa base de données, elle crée un objet de base de données, puis obtient un tas d'objets d'élément et les affiche sur la page? … En écrivant ceci, je me rends certainement compte à quel point je suis encore insensible à la POO. S'il vous plaît, aidez-moi à résoudre ce problème.

Si, à votre avis, ce n'est pas un bon projet pour commencer à patauger dans OOP avec, n'hésitez pas à suggérer une autre idée!

25
bernk

Honnêtement, je pense que les conseils donnés ici ont été terribles pour les nouveaux OO apprenants jusqu'à présent. Ce n'est pas une bonne idée de commencer immédiatement à considérer les objets comme des représentations d'une instance spécifique d'une "chose" définie par une certaine classe. Il est préférable de les considérer comme des composants compartimentés d'une machine qui ont une certaine interaction les uns avec les autres, mais pas les uns avec les autres. Chacun de ces composants maintient l'état

Si vous souhaitez utiliser un ORM (object-relationnel-mapping) pour les interactions de base de données, quel que soit le framework que vous utilisez ou créez aura probablement des objets peu profonds représentant des tables, qui sont probablement des collections de "choses", mais je n'aime pas personnellement les ORM , et je ne pense pas qu'ils représentent nécessairement des pratiques OO idéales, mais ils sont populaires pour les grandes applications Web.

En plus de cela, vous aurez probablement certains composants importants que la machine d'application Web doit exécuter, comme une ou plusieurs connexions DB (vous pouvez créer une classe qui maintient une connexion et vous pouvez exécuter des requêtes préparées à partir de - PDO est génial en soi, mais je l'envelopperais), et peut-être un système de modèles pour vos vues. Vous pouvez souhaiter que vos contrôleurs soient également des objets PHP. Si vous avez un formulaire à remplir, vous pouvez avoir un objet qui conserve les valeurs de formulaire pour P/R/G, une protection CSRF et peut effectuer une validation sur ses entrées.

Vous ne devriez pas essayer de chercher des "choses" à transformer en objets lors de la construction de la conception de votre application web et du graphique d'objet. Au lieu de cela, vous devriez penser aux composants logiques qui se réunissent pour le créer. Je ne pense pas que vous devriez essayer de forcer cela, et cela devrait venir assez naturellement, mais c'est très difficile à faire correctement et vous finirez certainement par devoir changer certaines décisions de conception en cours de route.

Mon dernier conseil est le suivant: la composition sur l'héritage est la voie à suivre.

17
Explosion Pills

Voici comment vous pouvez utiliser OOP pour acheter et vendre vos animaux de compagnie, la même méthodologie pourrait être utilisée pour vendre des voitures ou des avions; 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();
?>
9
Lawrence Cherone

Sur demande de l'OP, je partagerai mon code de livre d'or.
Classe de message:

<?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 d'objet d'accès aux données de message:

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

J'ai renommé certaines variables et fonctions pour vous donner un sens (traduit du néerlandais en anglais: P) afin que vous puissiez parfois trouver des phrases étranges parce que je viens de faire un remplacement rapide, etc. Amusez-vous avec. De plus, ce n'est pas tout le code car cela me ferait publier comme 20 fichiers de code: P

5
Bono

Comme mentionné par Explosion Pills, dans une application complexe, la plupart des objets concernent des composants d'application (par exemple, des pools de connexions de base de données, des commandes, des structures de données telles que des hashmaps) plutôt que des entités du monde réel (telles qu'une carte d'embarquement, une facture ou un fichier mp3 ). Il existe de nombreux bons livres sur les modèles de conception qui vous montrent comment les gens ont résolu de nombreux problèmes récurrents dans ce domaine. Le livre GOF tel qu'il est connu est complet mais très sec, les modèles de conception Head First peuvent être plus accessibles.

En termes d'analyse et de conception du monde réel. Il est souvent utile de penser en termes de noms et de verbes. Par exemple, une bibliothèque de prêt de vidéos (sont-elles obsolètes maintenant?) Peut avoir ces choses/noms:

  • Vidéo
  • Emprunteur

En termes de verbes:

  • Un emprunteur peut retirer une vidéo pendant une longue période
  • Un emprunteur peut retourner une vidéo au magasin, etc.

Ceux-ci peuvent ensuite être transformés en classes avec des opérations (cela fait longtemps que je n'ai fait aucun PHP donc je vais l'éviter):

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

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

Tout cela prend beaucoup de pratique et de jouer. La meilleure chose à faire est de rester coincé et d'apprendre des conceptions ratées. À mon avis OO est quelque chose que vous pouvez continuer à apprendre et à développer au cours de votre vie (ce n'est pas facile et il n'y a pas de solutions parfaites à quoi que ce soit). Un bon design est souvent itératif, alors attendez-vous à essayez quelques idées différentes pour votre application web "Craig's List".

3
mward

La meilleure chose à faire est de trouver un moyen de se concentrer sur le cœur de votre application - "post", "user", "post :: FindByName ()", "user-> Validate ()" etc., et ne vous inquiétez pas trop sur la plomberie - comment coller des articles aux tables de base de données, comment garder l'affichage pour un article cohérent entre les différentes recherches et comment coller le formulaire "entrer l'article" à un enregistrement de base de données.

Heureusement, il existe de nombreux frameworks qui font cela pour vous; le paradigme dominant dans les applications Web OO est "Model-View-Controller", également appelé MVC ; en PHP, il existe un certain nombre de frameworks MVC prêts à l'emploi que vous pouvez utiliser.

Bien que cela élargisse votre besoin d'apprendre - vous devez maintenant en savoir plus sur MVC ainsi que OO - cela signifie que vos efforts OO sont principalement limités à la " Couche "modèle", qui représente votre domaine d'activité; c'est là que OO est le plus naturel et expressif. La plupart des frameworks MVC vous permettent de définir votre couche "modèle", puis de créer automatiquement un site Web autour de cela en utilisant une technique connue sous le nom d'échafaudage - de cette façon, vous obtenez un moyen rapide d'expérimenter différentes implémentations pour votre modèle de domaine, sans avoir à décocher toute la plomberie.

1
Neville Kuyt