PHP 实现轻量级购物车类:仿 CodeIgniter 核心逻辑
本文详细解析基于 PHP 的手写购物车类实现,重点讲解如何利用数组结构结合 Session 进行状态存储,以及如何验证输入参数并自动计算购物车总额。
购物车核心功能与设计目标
在 Web 应用中,购物车是连接用户浏览与支付的关键模块。为了实现轻量且高效的购物车逻辑,本示例参考了 CodeIgniter 框架的设计思路,主要解决以下问题:
- 商品管理:支持单个或多个商品加入购物车,以及根据 RowID 调整或删除商品。
- 数据校验:对商品 ID、名称、价格和数量进行严格过滤,防止非法字符注入。
- 自动统计:实时更新购物车内的商品种类、总数量和总金额(Subtotal 与 Total)。
- 状态保持:利用
$_SESSION跨页面保持购物车状态。
第1步:构建 Cart 类基础结构
首先定义购物车类的核心属性。我们需要一个私有数组 $_cart_contents 来暂存当前会话的购物车数据,并配置正则表达式规则以确保存入的数据安全。
- product_id_rule:限制商品 ID 仅包含小写字母、数字及特殊符号
._-。 - product_name_rule:限制商品名称允许额外包含冒号
:。 - _cart_contents:核心存储数组,初始化为包含
cart_total和total_items的结构体。
第2步:实现商品插入逻辑 (insert)
插入功能是购物车的基础。该方法接受一维或多维数组输入,内部调用私有方法 _insert 处理单个商品。
- 参数校验:确保输入为有效数组且包含必填字段
id,qty,price,name。 - 数据清洗:
- 移除数量中的非数字字符及前导零。
- 移除价格中的非数字/小数点字符。
- 使用正则表达式验证 ID 和 Name 是否符合预设规则。 - 生成唯一标识 (RowID):
- 若商品存在options(如颜色、尺寸),则RowID = md5(id + options拼接)。
- 若无选项,则RowID = md5(id)。
这确保了同一商品的不同规格在购物车中被视为独立项。 - 保存至数组:将处理后的数据存入
$_cart_contents并以rowid为键。
第3步:实现购物车更新逻辑 (update)
当用户调整数量时,需调用 update 方法。该方法依赖商品唯一的 rowid 和目标新数量。
- 查找商品:根据传入的
rowid在$_cart_contents中定位对应商品。 - 数量处理:
- 同样进行数字清洗。
- 若新数量为 0,则从购物车中unset该商品(相当于删除)。
- 若数量大于 0 且与原数量不同,则更新数量字段。
第4步:自动统计与 Session 持久化
每次增删改操作后,必须重新计算统计数据并刷新 Session,以保证界面显示准确。
- 清除旧统计:重置
total_items和cart_total。 - 遍历计算:
- 遍历购物车数组,累加price * qty得到总金额。
- 同时为每个商品计算subtotal。 - 更新总量:
-total_items等于数组中实际商品键值的数量(排除统计字段)。
-cart_total为累加的总金额。 - 保存 Session:将整理好的
$_cart_contents写入$_SESSION['cart_contents']。若购物车为空(仅剩统计字段),则清空 Session 以释放资源。
第5步:其他辅助方法
- destroy():清空购物车数组并销毁 Session 中的购物车数据。
- contents() / total() / total_items():提供只读接口供视图层获取购物车详情。
- has_options():检查特定商品是否存在自定义属性。
完整代码实现
以下是完整的 Cart.php 类实现,可直接集成到项目中。
<?php
class Cart {
private $product_id_rule = '\.a-z0-9-_';
private $product_name_rule = '\.\:a-z0-9-_';
private $debug = TRUE;
private $_cart_contents = array();
public function __construct() {
if(isset($_SESSION['cart_contents'])) {
$this->_cart_contents = $_SESSION['cart_contents'];
} else {
$this->_cart_contents['cart_total'] = 0;
$this->_cart_contents['total_items'] = 0;
}
}
public function insert($items = array()) {
if( ! is_array($items) OR count($items) == 0) return FALSE;
$save_cart = FALSE;
if(isset($items['id'])) {
if($this->_insert($items) === TRUE) $save_cart = TRUE;
} else {
foreach($items as $val) {
if(is_array($val) AND isset($val['id'])) {
if($this->_insert($val) == TRUE) $save_cart = TRUE;
}
}
}
if($save_cart) {
$this->_save_cart();
return TRUE;
}
return FALSE;
}
public function update($items = array()) {
if( !is_array($items) OR count($items) == 0) return FALSE;
$save_cart = FALSE;
if(isset($items['rowid']) AND isset($items['qty'])) {
if($this->_update($items) === TRUE) $save_cart = TRUE;
} else {
foreach($items as $val) {
if(is_array($val) AND isset($val['rowid']) AND isset($val['qty'])) {
if($this->_update($val) === TRUE) $save_cart = TRUE;
}
}
}
if($save_cart) {
$this->_save_cart();
return TRUE;
}
return FALSE;
}
public function total() {
return $this->_cart_contents['cart_total'];
}
public function total_items() {
return $this->_cart_contents['total_items'];
}
public function contents() {
return $this->_cart_contents;
}
public function destroy() {
unset($this->_cart_contents);
$this->_cart_contents['cart_total'] = 0;
$this->_cart_contents['total_items'] = 0;
unset($_SESSION['cart_contents']);
}
private function has_options($rowid = '') {
if( ! isset($this->_cart_contents[$rowid]['options']) OR count($this->_cart_contents[$rowid]['options']) === 0) {
return FALSE;
}
return TRUE;
}
private function _insert($items = array()) {
if( ! is_array($items) OR count($items) == 0) return FALSE;
if( ! isset($items['id']) OR ! isset($items['qty']) OR ! isset($items['price']) OR ! isset($items['name'])) return FALSE;
// Sanitize Qty
$items['qty'] = trim(preg_replace('/([^0-9])/i', '', $items['qty']));
$items['qty'] = trim(preg_replace('/^([0]+)/i', '', $items['qty']));
if( ! is_numeric($items['qty']) OR $items['qty'] == 0) return FALSE;
// Validate ID
if( ! preg_match('/^['.$this->product_id_rule.']+$/i', $items['id'])) return FALSE;
// Validate Name
if( ! preg_match('/^['.$this->product_name_rule.']+$/i', $items['name'])) return FALSE;
// Sanitize Price
$items['price'] = trim(preg_replace('/([^0-9\.])/i', '', $items['price']));
$items['price'] = trim(preg_replace('/^([0]+)/i', '', $items['price']));
if( ! is_numeric($items['price'])) return FALSE;
// Generate RowID
if(isset($items['options']) AND count($items['options']) >0) {
$rowid = md5($items['id'].implode('', $items['options']));
} else {
$rowid = md5($items['id']);
}
// Add to cart
unset($this->_cart_contents[$rowid]);
$this->_cart_contents[$rowid]['rowid'] = $rowid;
foreach($items as $key => $val) {
$this->_cart_contents[$rowid][$key] = $val;
}
return TRUE;
}
private function _update($items = array()) {
if( ! isset($items['rowid']) OR ! isset($items['qty']) OR ! isset($this->_cart_contents[$items['rowid']])) return FALSE;
$items['qty'] = preg_replace('/([^0-9])/i', '', $items['qty']);
$items['qty'] = preg_replace('/^([0]+)/i', '', $items['qty']);
if( ! is_numeric($items['qty'])) return FALSE;
if($this->_cart_contents[$items['rowid']]['qty'] == $items['qty']) return FALSE;
if($items['qty'] == 0) {
unset($this->_cart_contents[$items['rowid']]);
} else {
$this->_cart_contents[$items['rowid']]['qty'] = $items['qty'];
}
return TRUE;
}
private function _save_cart() {
unset($this->_cart_contents['total_items']);
unset($this->_cart_contents['cart_total']);
$total = 0;
foreach($this->_cart_contents as $key => $val) {
if( ! is_array($val) OR ! isset($val['price']) OR ! isset($val['qty'])) continue;
$total += ($val['price'] * $val['qty']);
$this->_cart_contents[$key]['subtotal'] = ($val['price'] * $val['qty']);
}
$this->_cart_contents['total_items'] = count($this->_cart_contents);
$this->_cart_contents['cart_total'] = $total;
if(count($this->_cart_contents) <= 2) {
unset($_SESSION['cart_contents']);
return FALSE;
}
$_SESSION['cart_contents'] = $this->_cart_contents;
return TRUE;
}
}
?>
使用示例与测试
以下代码展示了如何实例化该类,插入带有可选属性的商品,并更新其数量。
<?php
session_start();
require_once('cart.php');
$items = array(
0 => array(
'id' => 'sp001',
'qty' => 20,
'price' => '10.50',
'name' => 'Product A',
'options' => array(
'color' => 'red',
'size' => 'L'
)
),
1 => array(
'id' => 'sp002',
'qty' => 1,
'price' => '3.50',
'name' => 'Product B'
)
);
$arr = array(
'rowid' => '生成的具体RowID值',
'qty' => 21
);
$cart = new Cart();
$cart->insert($items);
// $cart->update($arr); // 取消注释以测试更新
var_dump($cart->contents());
?>
通过以上步骤,您可以获得一个具备基本电商功能的轻量级购物车组件。该实现不依赖任何外部框架,易于移植和维护。以上就是 PHP 手写购物车类的详细内容,更多关于 PHP 面向对象编程的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









