如何将OOP概念应用于构建简单但真实的Web应用程序?[关闭]


25

我已经尝试了很长时间,将自己的头放在OOP上。我看到了它的优势。我阅读了很多很多教程,并观看了相同数量的有关该主题的视频。我得到了动物/猫/狗的例子,我得到了汽车/驱动器的例子。我苦苦挣扎的是如何在实际应用程序中应用这些概念。因此,我着手使用OOP构建一个。

我并不是在寻求语法或编写特定代码方面的帮助-我可以在文档中以及通过搜索论坛等方式找到自己。我真正需要的是一些指导,并时不时地朝着正确的方向发展。有经验丰富的程序员愿意指导我吗?

作为我的学习项目,我想构建一个简单的分类“ Web应用程序”。类似于Craigslist,但在范围方面被淡化。我想使用PHP5和MySQL,因为我对它们很熟悉。

假设只有以下两种用例:

  1. 发布要出售的东西
  2. 浏览/搜索要购买的东西

什么是事物“物”?我可以想象每个项目都可以是一个对象,但是在什么时候呢?又为什么呢

因此,例如,用户填写“待售物品”表格,该表格是否应该变成一个对象,然后传递给另一个将值插入数据库的对象?

当另一个用户正在浏览并要求查看C类的所有项目时该怎么办?是否有必要在应用程序必须连接到其数据库时创建一个数据库对象,然后获取一堆项目对象并将其显示在页面上,这是否有意义?……将其写出来无疑使我意识到我对OOP仍然一无所知。请帮我解决这个问题。

如果您认为这不是开始涉足OOP的好项目,请随时提出另一个想法!


1
我在同一条船上,我我了解OOP,因为我尝试Java已有一段时间了,但是当涉及到PHP时,我会知道如何立即以“正常”方式进行此类操作,但当涉及到如何思考时它将使用OOP来完成,我会失去生存的意愿。
martincarlin87

该表格没有变成一个对象。对象是类的实例。您可以这样看。$ item-> saveItem($ _ POST ['name'],$ _POST ['description']); 编辑真正帮助我弄清楚OOP的是创建一个简单的“ guestbook”网络应用程序。使用户登录,发帖,编辑信息,删除信息和搜索信息等

@pduersteler好主意,我该怎么做?诚然,这是我对stackoverflow的第一个问题:)

@Bono也许像您提到的留言簿应用程序确实是一个更好的起点。我在考虑的另一个应用程序是一个非常简单的列表应用程序,用户可以在其中登录,创建/编辑/删除列表,添加/编辑/删除这些列表中的项目。您介意与我们/我共享您的留言簿应用程序吗?

我不介意共享它,尽管这将是发布的大量代码。如果您愿意,我可以与您分享一个简单的示例类。同样,我也不知道这段代码的效果如何,因为坦率地说已经有一段时间了:P我将在下面发布它

Answers:


17

老实说,我认为到目前为止,这里的建议对于面向对象的新手来说是可怕的。立即开始将对象视为某个类定义的“事物”的特定实例的表示不是一个好主意。最好将它们视为机器的分隔组件,它们彼此之间有某种交互作用,但彼此之间没有内部交互作用。这些组件均保持状态

如果要对数据库交互使用ORM(对象关系映射),则无论您使用或创建的任何框架都可能会有一些浅表对象来表示表,这些表可能是“事物”的集合,但是我个人并不喜欢ORM。 ,但我认为它们不一定代表理想的面向对象实践,但它们在大型Web应用程序中很流行。

除此之外,您可能还会拥有Web应用程序机器需要运行的一些重要组件,例如一个或多个数据库连接(您可以创建一个维护连接的类,并可以从中运行准备好的查询,这PDO很不错) ,但我会把它包装起来),也许还有一个用于您视图的模板系统。您可能还希望控制器也是PHP对象。如果要填写表单,则可能有一个对象可以维护P / R / G的表单值(CSRF保护令牌),并可以对其输入执行验证。

在构建Web应用程序设计和对象图时,您不应尝试寻找将事物变成对象的“事物”。相反,您应该考虑一起创建逻辑组件的逻辑组件。我认为您不应该尝试强制这样做,并且应该自然而然地做到这一点,但是很难正确地做到这一点,您肯定会最终不得不在此过程中更改一些设计决策。

我的最终建议是:通过继承来构架是必经之路。


我的经验法则(特别是对于动态语言)是尝试仅在我想利用多态性的情况下创建类(即,如果这些类将实现同一方法的不同版本,并且逻辑将依赖于该类)不知何故)。否则,我会尝试以更“程序性”的风格来写,以保持简洁。
hugomg

9

这是您可以使用OOP买卖宠物的方法,可以使用相同的方法来出售汽车或飞机; 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
如果我再看到一个关于汽车或动物的常见例子,那我就丢了
尼尔·麦奎根

5

根据OP的要求,我将分享我的留言簿代码。
讯息类别:

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

消息数据访问对象类:

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

我重命名了一些对您有意义的变量和函数(从荷兰语译成英语:P),所以有时您可能会发现一些奇怪的感觉,因为我只是做了一个快速替换等。而且这不是整个代码,因为这将导致我发布价值20个文件的代码:P


3

正如爆炸药所提到的,在复杂的应用程序中,大多数对象与应用程序组件(例如数据库连接池,命令,数据结构(如哈希图))有关,而不是与现实世界中的实体(如登机证,发票或mp3文件)有关。 )。有许多关于设计模式的好书,向您展示了人们如何解决了这一领域中许多反复出现的问题。众所周知,GOF书很详尽,但是非常干燥,可能更容易掌握Head First Design Patterns。

在现实世界中进行分析和设计。用名词和动词来思考通常会很有帮助。例如,视频借阅库(现在已经过时了吗?)可能具有以下内容/名词:

  • 视频
  • 借款人

就动词而言:

  • 借款人可以长时间录制视频
  • 借款人可以将视频退还给商店等。

然后可以将它们转换为带有操作的类(因为我做过任何PHP已经很长时间了,所以我会避免使用它):

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

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

这一切都需要大量的练习和练习。最好的办法是陷入失败的设计中并从中学习。在我看来,OO是可以在您的一生中继续学习和发展的东西(这并不容易,并且没有完美的解决方案)。好的设计通常是反复进行的,因此期望为您的“克雷格列表”网络应用尝试一些不同的想法。


1

最好的办法是找到一种专注于应用程序核心的方法-“ post”,“ user”,“ post :: FindByName()”,“ user-> Validate()”等,而不用担心关于管道的太多内容-如何将帖子粘贴到数据库表,如何保持帖子在不同搜索之间的显示一致,以及如何将“输入帖子”表单粘贴到数据库记录。

幸运的是,有许多框架可以为您做到这一点;OO Web应用程序中的主要范例是“模型-视图-控制器”,也称为MVC;在PHP中,可以使用许多现成的MVC框架。

尽管这扩大了您的学习需求-现在您必须了解MVC和OO-这意味着您的OO工作主要限于表示您的业务领域的“模型”层。这就是OO最自然和最具表现力的地方。大多数MVC框架允许您定义“模型”层,然后使用称为脚手架的技术围绕该网站自动创建网站-这样,您可以快速尝试针对域模型进行不同实现的实验必须取消所有管道。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.