喜悦国际村 专业PHP开发者社区's Archiver

qh663 发表于 2006-9-10 03:49 AM

购物车类的设计

购物车类是商城程序一个非常重要的类。写类,就要继承其可以重复利用的思想,高效,扩展性好的特点。
首先,我们要明白要实现怎么样的功能。然后根据功能的需求用代码实现。商城程序的购物车的基本功能有:
        1、添加商品
        2、移除商品
        3、计算总额
不是吧!这么简单?呵呵,购物车流程的确如此。现在就用代码来实现这个过程。
一个商品的固定基本资料有:
        1、商品唯一ID号(id)
        2、商品名称(name)
        3、零售价(retail_price)
        4、销售价(price)
变动的资料有:
        1、商品数量(quantity)
        2、折扣额(discount)
        3、小计(subtotal)
全部商品统计的资料有:
        1、总数量
        2、总金额
        3、总折扣(告诉顾客共节省**元)
由于html是无状态语言。对于保存购物车的状态数据可以用SESSION、COOKIE、数据库、文本文件。通常只选一种方式保存,但是每一种保存方式都各有优点。为了使程序更通用、更实用,把存储状态的操作不写入购物车类中,就同时兼容上面几种方法!用数组来实现。
        $abc[唯一ID][商品名称]
        $abc[唯一ID][零售价]
        $abc[唯一ID][销售价]
        $abc[唯一ID][数量]
        $abc[唯一ID][折扣]
        $abc[唯一ID][小计]
如:
        Array
        (
                [1] => Array
                        (
                                [name] => 商品名称
                                [retail_price] => 60
                                [price] => 50
                                [quantity] => 4
                                [discount] => 40
                                [subtotal] => 200
                        )
        }
下面以session方式实例来说明一下,所需用到类的设计的结果。
session_start();//初始化session
$cat = new x_cart(&$_SESSION['merchandise']);//以引用方式保存购物车状态的变量,也可以用COOKIE或普通变量存数据库或文本文件。
$cat->add_item(array(123,'风扇',60,50),2) ;//添加一个商品与数量。第一个参数是数组,数组依次是id、商品名、零售价、销售价(可选,如果没有给出销售价则销售价就是零售价),第二个参数是商品数量
$cat->add_item(126,1);//同样的一个添加商品函数。有多种输入方式,增加程序操作的灵活性。第一个参数是商品id(可根据此ID自动调用商品名、零售价、销售价),第二个参数是数量
$cat->remove_item(123,1) ;//减商品数量。第一个参数是商品id,第二个是减数量。如果id资料不存在。则返回失败。如果减数量刚好是购物车中数量,则删除此商品。
$cat->dele_item(124);//移除商品ID的全部数量
$cat->edit_item(126,2);//编辑购物车中商品的数量
print_r($cat->sum_item());//返回购物车的总数量、总折扣、总金额
echo '<pre>';
print_r($_SESSION['merchandise']);
$cat->empty_cart();//清空购物车
由此可见,每个方法在类中是如何工作的。根据需要写相对应的代码。下面就带注释详细代码
[php]
//<meta charset=UTF-8">
/*
 * 类    名: cart
 * 功    能: 购物车类
 * 版    本: 1
 * 日    期: 2006年09月07日
  * 修改次数: 0
  * 最后修改: 2006年09月09日
 * 作    者: qh663
 * 版    权: 清晖
  * oicq号码: 80031807
  * 邮    箱: [email]qh8.net@163.com[/email]
  * 主    页: [url]http://qh8.net[/url]
 */
class cart
{
        var $items;
        var $total;
       
        /**
         *构造函数
         */
        function cart($varname){
                $this->items = &$varname;//引用,绑定变量变化
        }
        /**
         *添加商品基本资料(类内部操作,私有)
         *如果$item是数组型,并且有3或4个数量,则赋值。如果是数字型,则预留get_merchandise函数方法取得内容。
         *否则就是程序设计的严重失败。(如非设计错误,而是由用户私改变量,可以考虑禁用此操作的用户)
         */
        function add_merchandise($item) {
                if (is_array($item) and (count($item) == 4 ) or count($item) == 3){
                        $id = (int)current($item);
                        if($this->is_item($id) == false){
                                $this->items[$id]['name'] = (string)next($item);
                                $this->items[$id]['retail_price'] = next($item);
                                $price = next($item);
                                $this->items[$id]['price'] = empty($price)?$this->items[$id]['retail_price']:$price;
                        }
                        return $id;
                } elseif (is_numeric($item)){
                        if($this->is_item($item)){
                                return $item;
                        } else {
                                if ($item = $this->get_merchandise($item)){
                                        return $this->add_merchandise($item);
                                } else {
                                        die('无此商品');//如非设计错误,用户可能私改变量,可以考虑禁用此操作的用户
                                }
                        }
                } else {
                        die('商品参数不正确!');//如非设计错误,用户可能私改变量,可以考虑禁用此操作的用户
                }
        }
        /**
         *添加一个商品
         *$item 数字或数组(依次是id、商品名、零售价、销售价<可选>)
         *$num 数量
         */
        function add_item($item, $num) {
                $id = $this->add_merchandise($item);
                $this->items[$id]['quantity'] += $num;
                $this->items[$id]['discount'] = ($this->items[$id]['retail_price'] - $this->items[$id]['price']) * $this->items[$id]['quantity'];//更新折扣
                $this->items[$id]['subtotal'] = $this->items[$id]['quantity'] * $this->items[$id]['price'];//更新小计
                return true;
        }
        /**
         *减商品
         */
        function remove_item($id, $num) {
                if ($this->is_item($id) == false) return false;//检测是否在购物车中的物品
                if ($this->items[$id]['quantity'] > $num) {//如果购物车中的物品大于要减的数量
                        $this->items[$id]['quantity'] -= $num;//从购物车中减出
                        $this->items[$id]['discount'] = ($this->items[$id]['retail_price'] - $this->items[$id]['price']) * $this->items[$id]['quantity'];//更新折扣
                        $this->items[$id]['subtotal'] = $this->items[$id]['quantity'] * $this->items[$id]['price'];//更新小计
                        return true;
                } elseif ($this->items[$id]['quantity'] == $num) {//如果购物车中的物品等于要减的数量
                        unset($this->items[$id]);//删除购物车中该物品的所有资料
                        return true;
                } else {
                        return false;
                }
        }
        /**
         *编辑商品数量
         */
        function edit_item($id, $num) {
                if ($this->is_item($id) == false) return false;//检测是否在购物车中的物品
                if ($num > 0) {//保存0件以上的商品放在购物车里
                        $this->items[$id]['quantity'] = $num;
                        $this->items[$id]['discount'] = ($this->items[$id]['retail_price'] - $this->items[$id]['price']) * $this->items[$id]['quantity'];//更新折扣
                        $this->items[$id]['subtotal'] = $this->items[$id]['quantity'] * $this->items[$id]['price'];//更新小计
                        return true;
                } elseif ($num == 0) {//如果是0件
                        unset($this->items[$id]);//删除购物车中该物品的所有资料
                        return true;
                } else {
                        return false;
                }
        }
       
        /**
         *删除购物车中该物品的所有资料
         */
        function dele_item($id) {
                if ($this->is_item($id) == false) return false;
                unset($this->items[$id]);
                return true;
        }

        /**
         *检测购物车中该物品是否存在
         */
        function is_item($id) {
                return is_array($this->items[$id]);
        }
       
        /**
         *清空购物车
         */
        function empty_cart(){
        $this->items = NULL;
    }
       
        /**
         *预留方法接口,根据ID取得商品信息源
         */
        function get_merchandise($id){
                return false;
        }
        /**
         *统计购物车
         */
        function sum_item(){
                if (!is_array($this->items)) return false;
                foreach ($this->items as $value){
                        $total['quantity'] += $value['quantity'];//总数量
                        $total['discount'] += $value['discount'];//总折扣
                        $total['monny'] += $value['subtotal'];//总金额
                }
                $this->total = $total;
                return $total;
        }
       
}


class x_cart extends cart {
        /**
         *利用预留方法
         */
        function get_merchandise($id){
                $abc = array($id,'扩展',5.6,3.5);//此为测试数据,请用数据库操作取得相对应数组。
                return $abc;
        }
}
[/php]
由此可见,我的设计方法是:分析=>由类执行过程=>类代码实现=>完成
呵呵,想不到:time:写一篇贴子,用了3个小时……:Q:hug::L

fcicq 发表于 2006-9-10 09:46 AM

帮顶下.呵呵.

h058 发表于 2006-9-10 01:40 PM

清晖?以前在512j上碰到的?原来你到这边混了!呵呵~

qh663 发表于 2006-9-11 03:12 PM

[quote]原帖由 [i]h058[/i] 于 2006-9-10 13:40 发表
清晖?以前在512j上碰到的?原来你到这边混了!呵呵~ [/quote]
是的呀,想不到有人会记得我,:'(感动中,感觉还是中文妮称让人印象深刻…

h058 发表于 2006-9-11 07:23 PM

^_^转眼两年过去了!

redblade 发表于 2006-9-12 04:18 PM

我一直都在找这样子购物车的程序教程,唉
终于找到一个这么好的!
谢谢!!!

Matrix@Two_Max 发表于 2006-9-12 08:12 PM

在PHP部分版本或状态设置下,

以Session存储购物车未必是可行的。:)

可能需要更特殊的方法,以应付更复杂的环境。

但总体上,这种形式的购物车已能完成很大程度上的应用了:)

顶楼主一下。

php5 发表于 2006-9-13 05:33 PM

大多数情况下,是看的人多,真正用到购物车的人少

所以,SESSION 里面只要存个物品ID既可

显示时再查表,可能更能节省资源,也会安全一些

qh663 发表于 2006-9-14 12:49 PM

[quote]原帖由 [i]php5[/i] 于 2006-9-13 17:33 发表
大多数情况下,是看的人多,真正用到购物车的人少

所以,SESSION 里面只要存个物品ID既可

显示时再查表,可能更能节省资源,也会安全一些 [/quote]
看的人用不到购物车,购物的人才会用得到购物车。即时取商品资料是让顾客可以即时看到购物车里的状态。当然,如果不显示购物车即时状态,节省点资源,也可以改一下这个类使其更实用。

LuckLrj 发表于 2006-9-14 02:46 PM

我都存cookie里,显示的时候再查表,这样不管用户怎么选择,添加,删除商品,前端js操作cookie,
最后提交的时候才向服务器发送商品列表,这样前端,后端分开,很好维护。

php5 发表于 2006-9-14 03:02 PM

[quote]原帖由 [i]LuckLrj[/i] 于 2006-9-14 02:46 PM 发表
我都存cookie里,显示的时候再查表,这样不管用户怎么选择,添加,删除商品,前端js操作cookie,
最后提交的时候才向服务器发送商品列表,这样前端,后端分开,很好维护。 [/quote]

有可能禁用 cookie :L

shoujipeixun 发表于 2006-10-9 05:48 PM

顶上去!!!!!

fnet 发表于 2007-10-15 10:50 AM

一般还是存session吧,现在用cookie的地方少了

路人郝 发表于 2007-12-13 10:18 AM

学习了,谢谢楼主

psdshow 发表于 2007-12-13 10:58 AM

学习了
呵呵

changxiaob 发表于 2007-12-13 02:39 PM

ZENCART的购物车怎么样啊?

fnet 发表于 2007-12-14 06:18 PM

购物车是最典型的Session应用实例

个人更推荐对象式的写法:
/**
* 产品模型类
*/
class Model_ProductBean {
    var $id = 0; //id
    var $price = 0; // 单价
    var $name = null; //名城
    var $count = 1; //数量

    function setId( $id ) {
        $this->id = $id;
    }

    function getId() {
        return $this->id;
    }

    function setPrice( $price ) {
        $this->price = $price;
    }

    function getPrice() {
        return $this->price;
    }

    function setName( $name ) {
        $this->name = $name;
    }

    function getName() {
        return $this->name;
    }

    function setCount( $count ) {
        $this->count = $count;
    }

    /**
     * 获取商品数量
     *
     * @return int
     */
    function getCount() {
        return $this->count;
    }

    /**
     * 获取产品总价格
     *
     * @return double
     */
    function getTotalPrice() {
        return $this->count * $this->price;
    }
}

/**
* 对SESSION数据进行添加、删除、修改、统计
*
*/

class Helper_Cart {
   
    var $catName;

    function Helper_Cart( $catName = "" ) {
        if ($catName == "")
            $this->catName = "cat";
        else
            $this->catName = $catName;
    }

    /**
     * 检测产品是否存在
     *
     * @param int $id
     * @return boolean true/false
     */
    function checkProductExsist( $id ) {
        
        if ( 1 > count($_SESSION[$this->catName]) ) {
            return false;
        }
        
        foreach ($_SESSION[$this->catName] as $key=>$val) {
            if ($key == $id) {
                return true;
            }
        }
        return false;
    }

    /**
     * 保存一个产品对象
     *
     * @param Object(Model_Product) $oProdcut
     * @return int 产品个数
     */
    function setProduct( $id , $oProdcut ) {
        if ( !$this->checkProductExsist( $id ) ) {
            $_SESSION[$this->catName][$id] = $oProdcut;
            return 1;
        }
        
        $currentProduct = $_SESSION[$this->catName][$id];
        $currentCount = $currentProduct->getCount()+1;
        $currentProduct->setCount( $currentCount );
        return $currentCount;
    }

    /**
     * 根据产品id删除一个系列的产品
     *
     * @param int $id/-1 删除成功,返回删除id,删除不成功,返回-1
     */
    function removeProduct( $id ) {
        if ( $this->checkProductExsist($id) ) {
            unset( $_SESSION[$this->catName][$id] );
            return $id;
        } else {
            return -1;
        }
    }

    /**
     * 根据产品id删除一个产品
     *
     * @param int $id/-1 删除成功,返回删除的产品的id,没有这个商品,返回-1,商品正好为1个,则清楚这个id的商品 。
     */
    function decreaseProduct($id) {
        if ( !$this->checkProductExsist($id) ) {
            return -1 ;
        }

        $currentProduct = $_SESSION[$this->catName][$id];
        $currentCount = $currentProduct->getCount();


        if ($currentCount == 1) {
            unset($_SESSION[$this->catName][$id]);
            return $id;
        }

        $currentProduct->setCount( $currentCount-1 );
        return $id;
    }
   
    /**
     * 清空整个购物车
     *
     */
    function cleanCat() {
        if (isset($_SESSION[$this->catName])) {
            unset( $_SESSION[$this->catName] );
        }
        return true;
    }
   
    /**
     * 获取产品对象
     *
     * @param int $id
     * @return Object(Model_Product)
     */
    function getProduct( $id ) {
        return $_SESSION[$this->catName][$id];
    }
}

$oProduct1 = new Model_ProductBean();
$oProduct1->setId(1);
$oProduct1->setName("wazi");
$oProduct1->setPrice(123.00);

$oCat = new Helper_Cart();
$oCat->setProduct(1,$oProduct1);

$oProduct2 = new Model_ProductBean();
$oProduct2->setId(2);
$oProduct2->setName("toujing");
$oProduct2->setPrice(15.00);

$oCat->setProduct(2,$oProduct2);


$oProduct3 = new Model_ProductBean();
$oProduct3->setId(3);
$oProduct3->setName("xiezi");
$oProduct3->setPrice(23.00);

$oCat->setProduct(3,$oProduct3);

//$oCat->decreaseProduct(1);


$oProdcut = $oCat->getProduct(1);
$oProdcut2 = $oCat->getProduct(2);
$oProdcut3 = $oCat->getProduct(3);

echo $oProdcut->getTotalPrice()."\r\n";
echo $oProdcut2->getTotalPrice()."\r\n";
echo $oProdcut3->getTotalPrice()."\r\n";

print_r($_SESSION);

迷茫 发表于 2008-1-7 10:09 AM

写的好清楚阿 很方便 谢谢

1986xzw 发表于 2009-4-2 02:38 PM

这个购物车最后如果获取ID值。。比如print_r($_SESSION['merchandise']);打印出来Array
(
    [2422] => Array
        (
            [name] => 0004
            [retail_price] => 4
            [quantity] => 4
        )

    [2433] => Array
        (
            [name] => 0004
            [retail_price] => 4
            [quantity] => 4
        )

)

这ID值怎么获?

xingfou 发表于 2010-8-27 11:03 AM

谢谢楼主

页: [1] 2

Powered by Discuz! Archiver 7.0.0  © 2001-2009 Comsenz Inc.