PHP中使用多态替代条件语句实现多类型产品统一入库
PHP基于OOP多态实现通用产品入库方案
实现核心:通过抽象基类约定公共产品逻辑,各类型产品独立成类实现自身属性校验、持久化逻辑,配合工厂类自动匹配产品实例,全程无产品类型相关的条件判断,仅需单端点即可支持所有产品的入库操作。
数据库结构设计
按范式拆分公共表和各类型专属属性表:
- 公共产品表
products:存储所有产品共有字段
字段说明:product_id:主键,自增name:varchar类型,产品名称price:decimal类型,产品价格product_type:varchar类型,存储产品类型标识(laptop/tv/speakers)created_at:timestamp类型,创建时间,默认当前时间
- 各类型专属属性表:
laptop_attributes:存储笔记本专属属性,字段含product_id(外键关联products表主键)、cpu、ram、ssdtv_attributes:存储电视专属属性,字段含product_id(外键关联)、sizespeaker_attributes:存储音箱专属属性,字段含product_id(外键关联)、power、channels
类文件实现
所有产品类独立存放,核心依赖抽象类约束统一行为,靠多态分发逻辑。
1. 抽象产品基类 AbstractProduct.php
封装所有产品的公共属性校验、公共入库逻辑,强制子类实现自身专属逻辑:
<?php abstract class AbstractProduct { protected PDO $db; protected string $name; protected float $price; protected string $productType; public function __construct(PDO $db, string $name, float $price, string $productType) { $this->db = $db; $this->name = $name; $this->price = $price; $this->productType = $productType; $this->validateCommonAttributes(); } // 公共属性校验逻辑 protected function validateCommonAttributes(): void { if (trim($this->name) === '') { throw new InvalidArgumentException("产品名称不能为空"); } if ($this->price <= 0) { throw new InvalidArgumentException("产品价格必须大于0"); } } // 公共入库流程:先写公共表,再调子类方法写专属属性 public function save(): int { $stmt = $this->db->prepare("INSERT INTO products (name, price, product_type) VALUES (?, ?, ?)"); $stmt->execute([$this->name, $this->price, $this->productType]); $productId = (int)$this->db->lastInsertId(); $this->saveSpecificAttributes($productId); return $productId; } // 强制子类实现的抽象方法:专属属性校验、专属属性入库 abstract protected function validateSpecificAttributes(): void; abstract protected function saveSpecificAttributes(int $productId): void; }
2. 笔记本类 Laptop.php
独立类文件,实现笔记本专属的参数处理、校验、入库逻辑:
<?php class Laptop extends AbstractProduct { protected string $cpu; protected string $ram; protected string $ssd; public function __construct(PDO $db, array $params) { parent::__construct($db, $params['name'], (float)$params['price'], 'laptop'); $this->cpu = trim($params['cpu'] ?? ''); $this->ram = trim($params['ram'] ?? ''); $this->ssd = trim($params['ssd'] ?? ''); $this->validateSpecificAttributes(); } protected function validateSpecificAttributes(): void { if ($this->cpu === '' || $this->ram === '' || $this->ssd === '') { throw new InvalidArgumentException("笔记本需完整填写CPU、内存、硬盘参数"); } } protected function saveSpecificAttributes(int $productId): void { $stmt = $this->db->prepare("INSERT INTO laptop_attributes (product_id, cpu, ram, ssd) VALUES (?, ?, ?, ?)"); $stmt->execute([$productId, $this->cpu, $this->ram, $this->ssd]); } }
3. 电视类 TV.php
独立类文件,实现电视专属逻辑:
<?php class TV extends AbstractProduct { protected string $size; public function __construct(PDO $db, array $params) { parent::__construct($db, $params['name'], (float)$params['price'], 'tv'); $this->size = trim($params['size'] ?? ''); $this->validateSpecificAttributes(); } protected function validateSpecificAttributes(): void { if ($this->size === '') { throw new InvalidArgumentException("电视需填写尺寸参数"); } } protected function saveSpecificAttributes(int $productId): void { $stmt = $this->db->prepare("INSERT INTO tv_attributes (product_id, size) VALUES (?, ?)"); $stmt->execute([$productId, $this->size]); } }
4. 音箱类 Speakers.php
独立类文件,实现音箱专属逻辑:
<?php class Speakers extends AbstractProduct { protected string $power; protected string $channels; public function __construct(PDO $db, array $params) { parent::__construct($db, $params['name'], (float)$params['price'], 'speakers'); $this->power = trim($params['power'] ?? ''); $this->channels = trim($params['channels'] ?? ''); $this->validateSpecificAttributes(); } protected function validateSpecificAttributes(): void { if ($this->power === '' || $this->channels === '') { throw new InvalidArgumentException("音箱需完整填写功率、声道参数"); } } protected function saveSpecificAttributes(int $productId): void { $stmt = $this->db->prepare("INSERT INTO speaker_attributes (product_id, power, channels) VALUES (?, ?, ?)"); $stmt->execute([$productId, $this->power, $this->channels]); } }
5. 产品工厂类 ProductFactory.php
负责根据请求参数自动实例化对应产品类,是唯一维护类型和类映射关系的位置:
<?php class ProductFactory { // 类型映射表,后续新增产品类型仅需在此追加配置即可 protected static array $typeMap = [ 'laptop' => Laptop::class, 'tv' => TV::class, 'speakers' => Speakers::class ]; public static function create(PDO $db, array $params): AbstractProduct { $type = strtolower(trim($params['product_type'] ?? '')); if (!isset(self::$typeMap[$type])) { throw new InvalidArgumentException("不支持的产品类型"); } return new self::$typeMap[$type]($db, $params); } }
通用保存端点实现
仅需一个接口文件save_product.php,所有类型产品的新增请求都走这个端点,无任何类型判断逻辑:
<?php header('Content-Type: application/json'); try { // 初始化数据库连接 $db = new PDO( 'mysql:host=localhost;dbname=替换为你的库名;charset=utf8mb4', '替换为你的数据库账号', '替换为你的数据库密码' ); $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // 引入类文件,实际项目可使用composer自动加载替代手动引入 require_once 'AbstractProduct.php'; require_once 'Laptop.php'; require_once 'TV.php'; require_once 'Speakers.php'; require_once 'ProductFactory.php'; // 生成对应产品实例,调用save完成入库 $product = ProductFactory::create($db, $_POST); $productId = $product->save(); echo json_encode([ 'code' => 0, 'msg' => '保存成功', 'product_id' => $productId ], JSON_UNESCAPED_UNICODE); } catch (Exception $e) { http_response_code(400); echo json_encode([ 'code' => 1, 'msg' => $e->getMessage() ], JSON_UNESCAPED_UNICODE); }
实现说明
- 全程没有使用
if/else、switch等条件语句判断产品类型,不同产品的属性差异完全通过多态特性自动分发处理 - 每类产品对应独立类文件,耦合度低,后续新增产品类型只需要新增对应类文件、在工厂映射表追加配置,不需要修改原有逻辑和端点代码
- 所有产品新增请求统一走
save_product.php端点,不需要为不同产品类型单独开发接口 - 公共逻辑和专属逻辑拆分清晰,公共属性校验、入库逻辑在基类统一维护,避免重复代码
内容的提问来源于stack exchange,提问作者Dinesh
相关产品推荐
相关产品推荐

