Làm cách nào tôi có thể áp dụng các khái niệm OOP để xây dựng một ứng dụng web đơn giản nhưng thực tế? [đóng cửa]


25

Bây giờ tôi đã cố gắng rất lâu để quấn đầu quanh OOP. Tôi thấy lợi thế của nó. Tôi đã đọc nhiều, nhiều hướng dẫn và xem một số lượng video bằng nhau về chủ đề này. Tôi lấy ví dụ về động vật / mèo / chó, tôi lấy ví dụ về xe / lái xe. Điều tôi đang vật lộn là làm thế nào để áp dụng các khái niệm này trong một ứng dụng trong thế giới thực. Vì vậy, tôi đã bắt đầu xây dựng một cái bằng OOP.

Tôi không yêu cầu trợ giúp về cú pháp hoặc viết mã cụ thể - Tôi có thể thấy rằng bản thân mình trong tài liệu và bằng cách tìm kiếm các diễn đàn, v.v. Điều tôi thực sự cần là một số hướng dẫn, và thúc đẩy đúng hướng mọi lúc mọi nơi. Có lập trình viên dày dạn nào sẵn sàng tư vấn cho tôi không?

Là dự án học tập của tôi, tôi muốn xây dựng một "ứng dụng web" rao vặt đơn giản. Một cái gì đó tương tự như Craigslist nhưng cách giảm xuống về phạm vi. Tôi muốn sử dụng PHP5 và MySQL, vì tôi quen thuộc với chúng.

Giả sử chỉ có 2 trường hợp sử dụng này:

  1. Đăng một cái gì đó để bán
  2. Duyệt / tìm kiếm thứ gì đó để mua

"Những thứ" nên là đối tượng? Tôi có thể tưởng tượng rằng mỗi mục có thể là một đối tượng, nhưng vào thời điểm nào? Và tại sao?

Vì vậy, ví dụ, người dùng điền vào biểu mẫu "bài đăng để bán", liệu biểu mẫu đó có được chuyển thành một đối tượng được chuyển đến một đối tượng khác để chèn các giá trị vào cơ sở dữ liệu không?

Còn khi người dùng khác đang duyệt và yêu cầu xem tất cả các mục thuộc loại C thì sao? Liệu nó có ý nghĩa rằng bất cứ khi nào ứng dụng phải kết nối với cơ sở dữ liệu của nó, nó sẽ tạo ra một đối tượng cơ sở dữ liệu và sau đó lấy một loạt các đối tượng mục và hiển thị chúng trên trang? Viết ra điều này chắc chắn làm cho tôi nhận ra tôi vẫn không biết gì về OOP. Xin hãy giúp tôi sửa nó.

Nếu theo ý kiến ​​của bạn thì đây không phải là một dự án tốt để bắt đầu lội vào OOP, xin vui lòng đề xuất ý tưởng khác!


1
Tôi ở cùng một chiếc thuyền, tôi nghĩ rằng tôi hiểu OOP - đã được một thời gian kể từ khi tôi thử Java, nhưng khi nói đến PHP tôi sẽ biết cách làm những việc như thế này ngay lập tức theo cách 'bình thường' nhưng khi nghĩ về cách nó sẽ được thực hiện bằng cách sử dụng OOP Tôi mất ý chí sống.
martincarlin87

Các hình thức không được biến thành một đối tượng. Một đối tượng là một thể hiện của một lớp. Bạn có thể thấy nó như thế này. $ item-> saveItem ($ _ POST ['name'], $ _POST ['description']); chỉnh sửa Điều thực sự giúp tôi tìm ra OOP là tạo ra một ứng dụng web "sổ lưu bút" đơn giản. Làm cho người dùng đăng nhập, đăng tin nhắn, chỉnh sửa tin nhắn, xóa tin nhắn và tìm kiếm tin nhắn, v.v.

@pduersteler ý tưởng tốt, làm thế nào để tôi làm điều đó? Phải thừa nhận rằng đây là câu hỏi đầu tiên của tôi về stackoverflow :)

@Bono có thể một ứng dụng lưu bút như bạn đã đề cập thực sự là một nơi tốt hơn để bắt đầu. Một ứng dụng khác mà tôi đã nghĩ đến là một ứng dụng danh sách rất đơn giản nơi người dùng đăng nhập, tạo / chỉnh sửa / xóa danh sách, thêm / chỉnh sửa / xóa các mục trong danh sách đó. Bạn có phiền khi chia sẻ ứng dụng sổ lưu bút của bạn với chúng tôi / tôi không?

Tôi sẽ không phiền khi chia sẻ nó, mặc dù nó sẽ là một đoạn mã để đăng. Tôi có thể chia sẻ một lớp ví dụ đơn giản với bạn nếu bạn muốn. Ngoài ra tôi không biết mã này sẽ hoạt động tốt như thế nào, bởi vì thật lòng mà nói đã lâu rồi: P Tôi sẽ đăng nó bên dưới

Câu trả lời:


17

Tôi thành thật nghĩ rằng lời khuyên ở đây là khủng khiếp cho những người mới học OO cho đến nay. Không phải là một ý tưởng tốt để ngay lập tức bắt đầu nghĩ về các đối tượng như là các biểu diễn của một thể hiện cụ thể của một "vật" được định nghĩa bởi một số lớp. Tốt hơn nên nghĩ về chúng như các thành phần ngăn cách của một cỗ máy có một số tương tác với nhau, nhưng không phải là bên trong của nhau. Mỗi thành phần này duy trì trạng thái

Nếu bạn muốn sử dụng ORM (ánh xạ quan hệ đối tượng) cho các tương tác DB, bất kỳ khung nào bạn sử dụng hoặc tạo có thể sẽ có một số đối tượng nông đại diện cho các bảng, có thể là các bộ sưu tập "vật", nhưng tôi không thích ORMs cá nhân và tôi không nghĩ rằng chúng nhất thiết phải đại diện cho các hoạt động OO lý tưởng, nhưng chúng phổ biến cho các ứng dụng web lớn.

Ngoài ra, bạn có thể sẽ có một số thành phần quan trọng mà máy ứng dụng web cần chạy, chẳng hạn như một hoặc nhiều kết nối DB (bạn có thể tạo một lớp duy trì kết nối và bạn có thể chạy các truy vấn đã chuẩn bị từ - PDOrất tuyệt vời , nhưng tôi sẽ gói nó), và có lẽ là một hệ thống mẫu cho quan điểm của bạn. Bạn có thể muốn bộ điều khiển của mình cũng là đối tượng PHP. Nếu bạn có một biểu mẫu để điền vào, bạn có thể có một đối tượng duy trì các giá trị biểu mẫu cho P / R / G, mã thông báo bảo vệ CSRF và có thể thực hiện xác thực trên các đầu vào của nó.

Bạn không nên cố gắng tìm kiếm "những thứ" để biến thành các đối tượng khi xây dựng thiết kế ứng dụng web và đồ thị đối tượng của bạn. Thay vào đó, bạn nên suy nghĩ về các thành phần logic kết hợp với nhau để tạo ra nó. Tôi không nghĩ bạn nên cố gắng thực hiện điều này, và nó sẽ diễn ra khá tự nhiên, nhưng rất khó để thực hiện chính xác và bạn chắc chắn sẽ phải thay đổi một số quyết định thiết kế trên đường đi.

Lời khuyên cuối cùng của tôi là: sáng tác trên thừa kế là con đường để đi.


Một nguyên tắc nhỏ mà tôi có, đặc biệt đối với các ngôn ngữ động, là cố gắng chỉ tạo các lớp nếu tôi muốn tận dụng tính đa hình (nghĩa là, nếu các lớp đó sẽ triển khai các phiên bản khác nhau của cùng một phương thức và logic sẽ phụ thuộc vào điều đó bằng cách nào đó). Mặt khác, tôi cố gắng viết sai theo kiểu "thủ tục" hơn, để giữ cho nó đơn giản.
hugomg

9

Đây là cách bạn có thể sử dụng OOP để mua và bán thú cưng của mình, phương pháp tương tự có thể được sử dụng để bán ô tô hoặc máy bay; p

<?php
// define a superclass .. no instances will be made of 'animal' itself,
// but it is useful to define common characteristics and behaviours
// (ie: properties and methods) of all our classes of animals
class Animal {

    // this constructor function is called whenever a new instance
    // of the Animal class is created (or any class that inherits from Animal)
    function Animal ($colour) {

        // install the argument as an attribute of any instances of Animal
        $this->colour = $colour;
    }

    // this method will be available to all classes that inherit from Animal
    function report () {
        return "This ".$this->colour." ".get_class($this)." has ".$this->legs." legs.<br />";
    }
}

// this class inherits from Animal
class Cat extends Animal {

    // set the legs attribute
    public $legs = 4;

    // create a method that can be called from any instances of Cat
    function make_noise () {
        echo "MEOW!<br />";
    }
}

// this class inherits from Cat, and from Animal
class Panther extends Cat {

    // specifies the colour attribute
    public $colour = "black";

    // overwrites the constructor function that would otherwise be
    // inherited from Animal, with a blank constructor.
    function Panther () {}

    // overwrites the method inherited from Cat
    function make_noise () {
        echo "ROARRRR!<br />";
    }
}

// this class inherits from Animal
class Snake extends Animal {
    public $legs = 0;
}

// this class is unrelated to the others
class PetShop {

    // set up an array to store the pets that the shop will stock
    public $pets = array ();

    // set up a variable to store the total cash in the pet shop
    public $cash;

    // this method creates a new object and adds it to the pets array
    function add_pet ($petclass, $price, $colour) {

        // set up a variable containing the number of elements in the pets array
        $n_pets = count($this->pets);

        // add to the pets array, a new instance of the class specified as
        // the first argument in this method, using the last argument as the
        // colour argument that is passed to the specified class's constructor
        $this->pets[$n_pets] = new $petclass($colour);

        // add a 'price' attribute to the pet object
        $this->pets[$n_pets]->price = $price;
    }

    // this method removes the specified pet from the array and adds the price
    // to the pet shop's cash variable
    function sell_pet ($n) {

        // add pet's price to the cash total
        $this->cash += $this->pets[$n]->price;

        // remove the pet object from the array
        array_splice($this->pets, $n, 1);

        // give a message about the sale
        echo "SALE: Pet no. ".$n." sold. Total cash is now \$".$this->cash.".<br /><br />";
    }

    // this method reports on the pet shop's stock
    function show_pets () {

        // show the number of pets available
        echo "<B>Shop stock:</B><br />We have ".count($this->pets)." pets for sale.";
        echo "<br /><br />";

        // iterate through the pets array and show information about each one
        for ($i = 0; $i < count($this->pets); $i++) {
            echo "<B>Pet No. ".$i.": </b>".$this->pets[$i]->report();
            echo "Price: \$".$this->pets[$i]->price."<br />";
        }
        echo "<br />";
    }
}

// instantiate a new PetShop object
$shop = new PetShop ();

// add three pets to the shop
$shop->add_pet(cat, 20, "tabby");
$shop->add_pet(snake, 40, "brown");
$shop->add_pet(snake, 60, "black");

// show the pet's stock
$shop->show_pets();

// sell the first pet in the stock
$shop->sell_pet(0);

// show the pet's stock after the sale
$shop->show_pets();
?>

28
Nếu tôi thấy một ví dụ nữa với ô tô hoặc động vật, tôi sẽ mất nó
Neil McGuigan

5

Theo yêu cầu của OP, tôi sẽ chia sẻ mã lưu bút của mình.
Lớp tin nhắn:

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

Lớp đối tượng truy cập dữ liệu tin nhắn:

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

Tôi đã đổi tên một số biến và hàm để có ý nghĩa với bạn (dịch từ tiếng Hà Lan sang tiếng Anh: P) để đôi khi bạn có thể tìm thấy một số câu lạ vì tôi chỉ thay thế nhanh chóng, v.v. Hãy vui vẻ với nó. Ngoài ra, đây không phải là toàn bộ mã bởi vì điều đó sẽ dẫn đến việc tôi đăng tải như 20 tệp mã có giá trị: P


3

Như Exploding Pills đã đề cập, trong một ứng dụng phức tạp, hầu hết các đối tượng đều liên quan đến các thành phần ứng dụng (ví dụ: nhóm kết nối cơ sở dữ liệu, các lệnh, cấu trúc dữ liệu như hashmap) chứ không phải là các thực thể trong thế giới thực (như thẻ lên máy bay, hóa đơn hoặc tệp mp3 ). Có rất nhiều cuốn sách hay về các mẫu thiết kế chỉ cho bạn những cách mà mọi người đã giải quyết rất nhiều vấn đề định kỳ trong lĩnh vực này. Cuốn sách GOF như được biết là kỹ lưỡng nhưng rất khô khan, các mẫu thiết kế đầu tiên có thể dễ tiếp cận hơn.

Về mặt phân tích và thiết kế thế giới thực. Nó thường hữu ích để suy nghĩ về danh từ và động từ. Ví dụ: một thư viện cho vay video (hiện tại đã lỗi thời?) Có thể có những điều / danh từ này:

  • Video
  • Người vay

Về mặt động từ:

  • Người vay có thể lấy video ra trong một khoảng thời gian
  • Người vay có thể trả lại video cho cửa hàng, v.v.

Những thứ này sau đó có thể được biến thành các lớp với các hoạt động (đã lâu rồi kể từ khi tôi thực hiện bất kỳ PHP nào nên tôi sẽ tránh nó):

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

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

Tất cả cần rất nhiều thực hành và chơi xung quanh. Điều tốt nhất để làm là bị mắc kẹt và học hỏi từ các thiết kế thất bại. Theo tôi, OO là thứ mà bạn có thể tiếp tục học hỏi và phát triển trong suốt cuộc đời của mình (nó không dễ dàng và không có giải pháp hoàn hảo cho bất cứ điều gì). Thiết kế tốt thường lặp đi lặp lại, do đó, hãy thử dùng một vài ý tưởng khác nhau cho ứng dụng web "Danh sách của Craig".


1

Điều tốt nhất để làm là tìm cách tập trung vào cốt lõi của ứng dụng của bạn - "bài đăng", "người dùng", "bài đăng :: FindByName ()", "người dùng-> Xác thực ()", v.v. quá nhiều về hệ thống ống nước - cách dán bài vào bảng cơ sở dữ liệu, cách giữ màn hình cho bài đăng nhất quán giữa các tìm kiếm khác nhau và cách dán biểu mẫu "nhập bài" vào bản ghi cơ sở dữ liệu.

May mắn thay, có rất nhiều khung làm việc này cho bạn; mô hình chi phối trong các ứng dụng web OO là "Model-View-Controller", còn được gọi là MVC ; trong PHP, có một số khung MVC ngoài luồng bạn có thể sử dụng.

Trong khi điều này mở rộng nhu cầu tìm hiểu của bạn - bây giờ bạn phải tìm hiểu về MVC cũng như OO - điều đó có nghĩa là các nỗ lực OO của bạn chủ yếu bị ràng buộc với lớp "Model", đại diện cho lĩnh vực kinh doanh của bạn; đó là nơi mà OO là tự nhiên và biểu cảm nhất. Hầu hết các khung MVC cho phép bạn xác định lớp "mô hình" của mình và sau đó tự động tạo một trang web xung quanh bằng cách sử dụng một kỹ thuật được gọi là giàn giáo - bằng cách đó, bạn có thể thử nghiệm nhanh các cách triển khai khác nhau cho mô hình miền của mình mà không cần phải tháo tất cả các hệ thống ống nước.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.