Bagaimana saya bisa menerapkan konsep OOP untuk membangun aplikasi web yang sederhana namun nyata? [Tutup]

25

Saya sudah mencoba sekarang untuk waktu yang lama untuk membungkus kepala saya di sekitar OOP. Saya melihat kelebihannya. Saya sudah membaca banyak, banyak tutorial, dan menonton video dengan jumlah yang sama. Saya mendapatkan contoh hewan / kucing / anjing, saya mendapatkan contoh mobil / drive. Yang saya perjuangkan adalah bagaimana menerapkan konsep-konsep ini dalam aplikasi dunia nyata. Jadi, saya telah menetapkan untuk membangun satu menggunakan OOP.

Saya tidak meminta bantuan dengan sintaks atau menulis kode khusus - saya dapat menemukan diri saya dalam dokumentasi dan dengan mencari forum dll. Apa yang saya benar-benar butuhkan adalah beberapa panduan, dan dorongan ke arah yang benar setiap sekarang dan kemudian. Apakah ada programmer berpengalaman yang mau membimbing saya?

Sebagai proyek pembelajaran saya, saya ingin membuat "aplikasi web" sederhana. Sesuatu yang mirip dengan Craigslist tetapi cara dipermudah dalam hal ruang lingkup. Saya ingin menggunakan PHP5 dan MySQL, karena saya kenal dengan mereka.

Katakanlah hanya ada 2 kasus penggunaan ini:

  1. Posting sesuatu untuk dijual
  2. Menjelajah / mencari sesuatu untuk dibeli

"Benda" apa yang seharusnya menjadi objek? Saya bisa membayangkan bahwa setiap item bisa menjadi objek, tetapi pada titik apa? Dan mengapa?

Jadi misalnya, pengguna mengisi formulir "pos barang untuk dijual", haruskah formulir itu diubah menjadi objek yang diteruskan ke objek lain yang memasukkan nilai ke dalam basis data?

Bagaimana bila pengguna lain browsing dan permintaan untuk melihat semua item dari kategori C? Apakah masuk akal bahwa setiap kali aplikasi harus terhubung ke database-nya, ia menciptakan objek database dan kemudian mendapatkan banyak objek item dan menampilkannya di halaman? ... menulis ini keluar tentu membuat saya menyadari betapa mengerti aku masih tentang OOP. Tolong bantu saya memperbaikinya.

Jika menurut Anda ini bukan proyek yang baik untuk mulai mengarungi OOP, jangan ragu untuk menyarankan ide lain!

bernk
sumber
1
Saya berada di kapal yang sama, saya pikir saya mengerti OOP - sudah lama sejak saya mencoba Java, tetapi ketika datang ke PHP saya akan tahu bagaimana melakukan hal-hal seperti ini langsung dengan cara 'normal' tetapi ketika datang untuk memikirkan bagaimana itu akan dilakukan menggunakan OOP saya kehilangan keinginan untuk hidup.
martincarlin87
Bentuknya tidak berubah menjadi objek. Objek adalah turunan dari kelas. Anda bisa melihatnya seperti ini. $ item-> saveItem ($ _ POST ['name'], $ _POST ['description']); sunting Apa yang benar-benar membantu saya mengetahui OOP adalah membuat aplikasi web "buku tamu" sederhana. Buat pengguna masuk, memposting pesan, mengedit pesan, menghapus pesan, dan mencari pesan, dll.
@pduersteler ide bagus, bagaimana saya bisa melakukan itu? Memang, ini adalah pertanyaan pertama saya di stackoverflow :)
@Bono mungkin aplikasi buku tamu seperti yang Anda sebutkan memang tempat yang lebih baik untuk memulai. Yang lain yang saya pikirkan adalah aplikasi daftar yang sangat sederhana di mana pengguna masuk, membuat / mengedit / menghapus daftar, menambah / mengedit / menghapus item dalam daftar tersebut. Maukah Anda berbagi aplikasi buku tamu Anda dengan kami / saya?
Saya tidak keberatan membagikannya, meskipun itu akan menjadi sebuah loooot kode untuk dikirim. Saya bisa membagikan kelas contoh sederhana dengan Anda jika Anda mau. Juga saya tidak tahu seberapa baik kode ini akan bekerja, karena terus terang sudah lama: P Saya akan mempostingnya di bawah ini

Jawaban:

17

Sejujurnya saya berpikir bahwa saran di sini sangat buruk bagi pelajar OO baru sejauh ini. Bukan ide yang baik untuk segera mulai memikirkan objek sebagai representasi dari contoh spesifik "sesuatu" yang didefinisikan oleh beberapa kelas. Lebih baik untuk menganggap mereka sebagai komponen terkotak dari mesin yang memiliki beberapa interaksi satu sama lain, tetapi tidak internal satu sama lain. Masing-masing komponen ini mempertahankan status

Jika Anda ingin menggunakan ORM (object-relational-mapping) untuk interaksi DB, kerangka apa pun yang Anda gunakan atau buat mungkin akan memiliki beberapa objek dangkal yang mewakili tabel, yang mungkin merupakan kumpulan dari "hal-hal," tapi saya tidak suka ORM secara pribadi , dan saya tidak berpikir mereka mewakili praktik OO yang ideal, tetapi mereka populer untuk aplikasi web besar.

Selain itu, Anda mungkin akan memiliki beberapa komponen penting yang harus dijalankan oleh mesin aplikasi web seperti satu atau lebih koneksi DB (Anda dapat membuat kelas yang mempertahankan koneksi dan Anda dapat menjalankan kueri yang disiapkan dari - PDOsangat bagus dengan sendirinya , tapi saya akan membungkusnya), dan mungkin sistem template untuk pandangan Anda. Anda mungkin ingin pengontrol Anda menjadi objek PHP juga. Jika Anda memiliki bentuk untuk mengisi, Anda mungkin memiliki objek yang mempertahankan nilai-nilai bentuk untuk P / R / G, token CSRF perlindungan, dan dapat melakukan validasi pada input.

Anda seharusnya tidak mencoba mencari "benda" untuk berubah menjadi objek saat membuat desain aplikasi web dan grafik objek. Sebagai gantinya, Anda harus memikirkan komponen logis yang datang bersama-sama untuk membuatnya. Saya tidak berpikir Anda harus mencoba untuk memaksakan ini, dan itu harus datang secara alami, tetapi sangat sulit untuk dilakukan dengan benar dan Anda pasti akan harus mengubah beberapa keputusan desain di sepanjang jalan.

Saran terakhir saya adalah ini: komposisi atas warisan adalah cara untuk pergi.

Pil Ledakan
sumber
Aturan praktis yang saya miliki, khususnya untuk bahasa dinamis, adalah mencoba untuk hanya membuat kelas jika saya ingin mengambil keuntungan dari polimorfisme (yaitu, jika kelas-kelas itu akan mengimplementasikan versi berbeda dari metode yang sama, dan logika akan bergantung pada itu entah bagaimana). Kalau tidak, saya mencoba melakukan kesalahan dalam menulis dengan gaya yang lebih "prosedural", agar tetap sederhana.
hugomg
9

Inilah cara Anda dapat menggunakan OOP untuk membeli dan menjual hewan peliharaan Anda, metodologi yang sama dapat digunakan untuk menjual mobil atau pesawat; 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
sumber
28
Jika saya melihat satu lagi contoh oop dengan mobil atau hewan, saya akan kehilangan itu
Neil McGuigan
5

Atas permintaan OP, saya akan membagikan kode buku tamu saya.
Kelas pesan:

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

Kelas Objek Akses Data Pesan:

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

Saya mengganti nama beberapa variabel dan fungsi agar masuk akal bagi Anda (diterjemahkan dari bahasa Belanda ke bahasa Inggris: P) sehingga Anda mungkin menemukan beberapa kalimat aneh kadang-kadang karena saya baru saja mengganti yang cepat dll. Selamat bersenang-senang dengannya. Juga ini bukan seluruh kode karena itu akan menghasilkan saya memposting seperti 20 file kode: P

Bono
sumber
3

Seperti yang disebutkan oleh Explosion Pills, dalam aplikasi yang kompleks sebagian besar objek berhubungan dengan komponen aplikasi (misalnya kumpulan koneksi database, perintah, struktur data seperti hashmaps) daripada entitas dunia nyata (seperti boarding pass, faktur, atau file mp3) ). Ada banyak buku bagus tentang pola desain yang menunjukkan kepada Anda cara orang telah memecahkan banyak masalah berulang di bidang ini. Buku GOF seperti diketahui menyeluruh tetapi sangat kering, Head First Design Patterns mungkin lebih mudah diakses.

Dalam hal analisis dan desain dunia nyata. Seringkali bermanfaat untuk berpikir dalam kata benda dan kata kerja. Misalnya perpustakaan pinjam video (apakah ini sudah usang sekarang?) Mungkin memiliki benda / kata benda ini:

  • Video
  • Peminjam

Dalam hal kata kerja:

  • Peminjam dapat mengambil video untuk waktu yang lama
  • Peminjam dapat mengembalikan video ke toko dll.

Ini kemudian dapat diubah menjadi kelas dengan operasi (sudah lama sejak saya melakukan PHP jadi saya akan menghindarinya):

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

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

Itu semua membutuhkan BANYAK latihan dan bermain-main. Hal terbaik untuk dilakukan adalah terjebak dan belajar dari desain yang gagal. Menurut pendapat saya, OO adalah sesuatu yang dapat terus Anda pelajari dan kembangkan sepanjang hidup Anda (itu tidak mudah dan tidak ada solusi sempurna untuk apa pun). Desain yang bagus sering kali berulang, jadi cobalah beberapa ide berbeda untuk aplikasi web "Craig's List" Anda.

mward
sumber
1

Hal terbaik untuk dilakukan adalah menemukan cara untuk berkonsentrasi pada inti aplikasi Anda - "posting", "pengguna", "posting :: FindByName ()", "user-> Validate ()" dll, dan jangan khawatir terlalu banyak tentang saluran air - cara merekatkan posting ke tabel basis data, cara menjaga tampilan agar posting konsisten di antara berbagai pencarian, dan cara merekatkan formulir "masukkan posting" ke catatan database.

Untungnya, ada banyak kerangka kerja yang melakukan ini untuk Anda; paradigma dominan dalam aplikasi web OO adalah "Model-View-Controller", juga dikenal sebagai MVC ; di PHP, ada sejumlah kerangka kerja MVC off-the-shelf yang dapat Anda gunakan.

Sementara ini memperluas kebutuhan Anda untuk belajar - Anda sekarang harus belajar tentang MVC dan juga OO - itu berarti bahwa upaya OO Anda sebagian besar dibatasi pada lapisan "Model", yang mewakili domain bisnis Anda; di situlah OO paling alami dan ekspresif. Sebagian besar kerangka kerja MVC memungkinkan Anda untuk menentukan lapisan "model" Anda, dan kemudian secara otomatis membuat situs web di sekitarnya yang menggunakan teknik yang dikenal sebagai perancah - dengan cara itu, Anda mendapatkan cara cepat bereksperimen dengan berbagai implementasi untuk model domain Anda, tanpa harus menghapus semua pipa ledeng.

Neville Kuyt
sumber