¿Cómo puedo aplicar los conceptos de OOP para crear una aplicación web simple pero real? [cerrado]

25

He intentado durante mucho tiempo entender cómo funciona la OOP. Veo sus ventajas. He leído muchos tutoriales y he visto la misma cantidad de videos sobre el tema. Obtengo los ejemplos de animales / gatos / perros, obtengo los ejemplos de automóviles / unidades. Con lo que estoy luchando es cómo aplicar estos conceptos en una aplicación del mundo real. Entonces, me propuse construir uno usando OOP.

No estoy pidiendo ayuda con la sintaxis o escribiendo código específico. Puedo encontrarlo en la documentación y buscando en foros, etc. Lo que realmente necesito es orientación y un empujón en la dirección correcta de vez en cuando. ¿Hay algún programador experimentado dispuesto a guiarme?

Como mi proyecto de aprendizaje, me gustaría construir una "aplicación web" de clasificados simples. Algo similar a Craigslist pero muy diluido en términos de alcance. Me gustaría usar PHP5 y MySQL, porque estoy familiarizado con ellos.

Digamos que solo hay estos 2 casos de uso:

  1. Publicar algo para la venta
  2. Navegar / buscar algo para comprar

¿Qué "cosas" deberían ser objetos? Me imagino que cada elemento podría ser un objeto, pero ¿en qué punto? ¿Y por qué?

Entonces, por ejemplo, el usuario completa el formulario "publicar artículo en venta", ¿debería ese formulario convertirse en un objeto que se pasa a otro objeto que inserta los valores en una base de datos?

¿Qué pasa cuando otro usuario está navegando y solicita ver todos los elementos de la categoría C? ¿Tiene sentido que cada vez que la aplicación tiene que conectarse a su base de datos crea un objeto de base de datos y luego obtiene un montón de objetos de elementos y los muestra en la página? ... escribir esto ciertamente me hace darme cuenta de lo despistado que todavía estoy sobre la POO. Por favor, ayúdame a arreglar eso.

Si, en su opinión, este no es un buen proyecto para comenzar a meterse en OOP, ¡no dude en sugerir otra idea!

bernk
fuente
1
Estoy en el mismo barco, creo que entiendo la POO: ha pasado un tiempo desde que intenté Java, pero cuando se trata de PHP sabría cómo hacer cosas como esta al instante de la manera 'normal', pero cuando se trata de pensar cómo se haría usando POO. Pierdo la voluntad de vivir.
martincarlin87
El formulario no se convierte en un objeto. Un objeto es una instancia de una clase. Podrías verlo así. $ item-> saveItem ($ _ POST ['nombre'], $ _POST ['descripción']); editar Lo que realmente me ayudó a descubrir OOP es crear una aplicación web simple de "libro de visitas". Hacer que los usuarios inicien sesión, publiquen mensajes, editen mensajes, eliminen mensajes y busquen mensajes, etc.
@pduersteler buena idea, ¿cómo hago para hacer eso? Es cierto que esta es mi primera pregunta sobre stackoverflow :)
@Bono tal vez una aplicación de libro de visitas como usted mencionó es de hecho un mejor lugar para comenzar. La otra en la que estaba pensando era una aplicación de lista muy simple donde los usuarios inician sesión, hacen / editan / eliminan listas, agregan / editan / eliminan elementos en esas listas. ¿Te importaría compartir tu aplicación de libro de visitas con nosotros / yo?
No me importaría compartirlo, aunque sería un montón de código para publicar. Podría compartir una clase de ejemplo simple con usted si lo desea. Además, no sé qué tan bien funcionará este código, porque francamente ha pasado un tiempo: P Lo publicaré a continuación

Respuestas:

17

Sinceramente, creo que el consejo aquí ha sido terrible para los nuevos estudiantes de OO hasta ahora. No es una buena idea comenzar a pensar de inmediato en los objetos como representaciones de una instancia específica de una "cosa" definida por alguna clase. Es mejor pensar en ellos como componentes compartimentados de una máquina que tienen alguna interacción entre ellos, pero no los componentes internos de los demás. Cada uno de estos componentes mantiene el estado

Si desea utilizar un ORM (mapeo relacional de objetos) para las interacciones de DB, cualquier marco que use o cree probablemente tendrá algunos objetos superficiales que representan tablas, que probablemente sean colecciones de "cosas", pero personalmente no me gustan los ORM , y no creo que necesariamente representen prácticas ideales de OO, pero son populares para grandes aplicaciones web.

Además de eso, probablemente tendrá algunos componentes importantes que la máquina de aplicaciones web necesita para ejecutar, como una o más conexiones de base de datos (puede crear una clase que mantenga una conexión y puede ejecutar consultas preparadas desde - PDOes genial por sí mismo , pero lo envolvería), y quizás un sistema de plantillas para sus vistas. Es posible que también desee que sus controladores sean objetos PHP. Si tiene que completar un formulario, puede tener un objeto que mantenga los valores del formulario para P / R / G, un token de protección CSRF, y pueda realizar la validación en sus entradas.

No debe intentar buscar "cosas" para convertirlas en objetos al construir el diseño de su aplicación web y el gráfico de objetos. En cambio, debe pensar en los componentes lógicos que se unen para crearlo. No creo que deba intentar forzar esto, y debería ser bastante natural, pero es muy difícil hacerlo correctamente y definitivamente tendrá que cambiar algunas decisiones de diseño en el camino.

Mi consejo final es este: la composición sobre la herencia es el camino a seguir.

Píldoras de explosión
fuente
Una regla general que tengo, especialmente para lenguajes dinámicos, es intentar crear solo clases si quiero aprovechar el polimorfismo (es decir, si esas clases implementarán diferentes versiones del mismo método, y la lógica dependerá de eso de alguna manera). De lo contrario, trato de equivocarme al escribir en un estilo más "de procedimiento", para que sea simple.
hugomg
9

Así es como puede usar OOP para comprar y vender sus mascotas, la misma metodología podría usarse para vender autos o aviones; 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();
?>
Lawrence Cherone
fuente
28
Si veo un ejemplo más con autos o animales, lo perderé
Neil McGuigan
5

A petición de OP, compartiré el código de mi libro de visitas.
Clase de mensaje:

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

Clase de objeto de acceso a datos de mensaje:

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

Cambié el nombre de algunas de las variables y funciones para que tengan sentido (traducido del holandés al inglés: P) para que pueda encontrar algunas sesiones extrañas a veces porque acabo de hacer un reemplazo rápido, etc. Diviértase con eso. Además, este no es todo el código porque eso me daría como resultado publicar un código de 20 archivos: P

Bono
fuente
3

Como se menciona en Explosion Pills, en una aplicación compleja, la mayoría de los objetos están relacionados con componentes de la aplicación (por ejemplo, grupos de conexiones de bases de datos, comandos, estructuras de datos como hashmaps) en lugar de entidades del mundo real (como una tarjeta de embarque, una factura o un archivo mp3) ) Hay muchos buenos libros sobre patrones de diseño que muestran formas en que las personas han resuelto muchos problemas recurrentes en esta área. El libro GOF, como se le conoce, es completo pero muy seco, los patrones de diseño de Head First pueden ser más accesibles.

En términos de análisis y diseño del mundo real. A menudo es útil pensar en términos de sustantivos y verbos. Por ejemplo, una biblioteca de préstamos de video (¿son obsoletos ahora?) Puede tener estos elementos / sustantivos:

  • Vídeo
  • Prestatario

En términos de verbos:

  • Un prestatario puede sacar un video por un período de tiempo prolongado
  • Un prestatario puede devolver un video a la tienda, etc.

Estos se pueden convertir en clases con operaciones (hace mucho tiempo que no hago PHP, así que lo evitaré):

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

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

Todo toma MUCHA práctica y jugar. Lo mejor que puede hacer es quedarse atrapado y aprender de los diseños fallidos. En mi opinión, OO es algo que puedes seguir aprendiendo y desarrollando a lo largo de tu vida (no es fácil y no hay soluciones perfectas para nada). El buen diseño es a menudo iterativo, así que espere probar algunas ideas diferentes para su aplicación web "Craig's List".

mward
fuente
1

Lo mejor que puede hacer es encontrar una manera de concentrarse en el núcleo de su aplicación: "post", "user", "post :: FindByName ()", "user-> Validate ()" etc., y no se preocupe demasiado sobre la plomería: cómo pegar las publicaciones en las tablas de la base de datos, cómo mantener la visualización de una publicación coherente entre las diferentes búsquedas y cómo pegar el formulario "ingresar publicación" en un registro de la base de datos.

Afortunadamente, hay muchos marcos que hacen esto por usted; el paradigma dominante en las aplicaciones web OO es "Model-View-Controller", también conocido como MVC ; en PHP, hay una serie de marcos MVC disponibles que puede usar.

Si bien esto amplía su necesidad de aprender, ahora debe aprender sobre MVC y OO, significa que sus esfuerzos de OO se limitan principalmente a la capa "Modelo", que representa su dominio comercial; ahí es donde OO es más natural y expresivo. La mayoría de los marcos MVC le permiten definir su capa de "modelo" y luego crear automáticamente un sitio web en torno a eso utilizando una técnica conocida como andamiaje; de ​​esa manera, obtiene una forma rápida de experimentar con diferentes implementaciones para su modelo de dominio, sin tener que quitar toda la fontanería.

Neville Kuyt
fuente