PHP面向对象编程实战:构建MVC电商系统架构 | 后端开发教程

2025-10-07 0 773

现代PHP开发:从过程式到面向对象的演进

PHP语言经历了从简单的脚本语言到成熟的企业级开发语言的蜕变。现代PHP开发强调面向对象编程(OOP)、设计模式应用和架构设计,本教程将通过构建一个完整的电商系统来展示这些先进理念。

技术栈概览:

  • PHP 8.1+:新特性如枚举、只读属性、纤程
  • Composer:现代化的依赖管理工具
  • PDO:安全的数据库操作接口
  • MVC模式:清晰的分层架构
  • 命名空间:代码组织和自动加载

电商系统项目结构设计

首先创建清晰的项目目录结构,这是良好架构的基础:

ecommerce-system/
├── app/
│   ├── Controllers/
│   │   ├── ProductController.php
│   │   ├── UserController.php
│   │   └── OrderController.php
│   ├── Models/
│   │   ├── Product.php
│   │   ├── User.php
│   │   └── Order.php
│   ├── Views/
│   │   ├── products/
│   │   ├── users/
│   │   └── layouts/
│   └── Core/
│       ├── Router.php
│       ├── Database.php
│       └── Validator.php
├── config/
│   ├── database.php
│   └── app.php
├── public/
│   └── index.php
├── vendor/
└── composer.json

核心组件实现:从数据库到路由

1. 数据库连接层(使用PDO和单例模式)

<?php
namespace AppCore;

class Database
{
    private static ?Database $instance = null;
    private PDO $connection;
    
    private function __construct()
    {
        $config = require __DIR__ . '/../../config/database.php';
        
        $dsn = "mysql:host={$config['host']};dbname={$config['database']};charset={$config['charset']}";
        
        $this->connection = new PDO($dsn, $config['username'], $config['password'], [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
            PDO::ATTR_EMULATE_PREPARES => false
        ]);
    }
    
    public static function getInstance(): Database
    {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    
    public function getConnection(): PDO
    {
        return $this->connection;
    }
    
    // 防止克隆和反序列化
    private function __clone() {}
    public function __wakeup() {}
}
?>

2. 智能路由系统

<?php
namespace AppCore;

class Router
{
    private array $routes = [];
    private array $middlewares = [];
    
    public function add(string $method, string $path, array $handler): void
    {
        $this->routes[] = [
            'method' => strtoupper($method),
            'path' => $this->normalizePath($path),
            'handler' => $handler,
            'middlewares' => $this->middlewares
        ];
        
        // 重置中间件
        $this->middlewares = [];
    }
    
    public function middleware(string $middleware): self
    {
        $this->middlewares[] = $middleware;
        return $this;
    }
    
    public function dispatch(string $method, string $path): void
    {
        $method = strtoupper($method);
        $path = $this->normalizePath($path);
        
        foreach ($this->routes as $route) {
            if ($this->matchRoute($route, $method, $path)) {
                $this->executeHandler($route);
                return;
            }
        }
        
        http_response_code(404);
        echo "页面未找到";
    }
    
    private function matchRoute(array $route, string $method, string $path): bool
    {
        return $route['method'] === $method && $route['path'] === $path;
    }
    
    private function executeHandler(array $route): void
    {
        [$controllerClass, $method] = $route['handler'];
        
        // 执行中间件
        foreach ($route['middlewares'] as $middleware) {
            $middlewareInstance = new $middleware();
            if (!$middlewareInstance->handle()) {
                return;
            }
        }
        
        $controller = new $controllerClass();
        $controller->$method();
    }
    
    private function normalizePath(string $path): string
    {
        return '/' . trim($path, '/');
    }
}
?>

MVC模式深度实现

1. 产品模型(使用Active Record模式)

<?php
namespace AppModels;

use AppCoreDatabase;

class Product
{
    private PDO $db;
    public ?int $id = null;
    public string $name;
    public string $description;
    public float $price;
    public int $stock;
    public DateTime $created_at;
    
    public function __construct()
    {
        $this->db = Database::getInstance()->getConnection();
    }
    
    public function save(): bool
    {
        if ($this->id === null) {
            return $this->create();
        }
        return $this->update();
    }
    
    private function create(): bool
    {
        $sql = "INSERT INTO products (name, description, price, stock) 
                VALUES (:name, :description, :price, :stock)";
        
        $stmt = $this->db->prepare($sql);
        $result = $stmt->execute([
            'name' => $this->name,
            'description' => $this->description,
            'price' => $this->price,
            'stock' => $this->stock
        ]);
        
        if ($result) {
            $this->id = (int)$this->db->lastInsertId();
        }
        
        return $result;
    }
    
    public static function find(int $id): ?Product
    {
        $db = Database::getInstance()->getConnection();
        $sql = "SELECT * FROM products WHERE id = ?";
        $stmt = $db->prepare($sql);
        $stmt->execute([$id]);
        
        $data = $stmt->fetch();
        if (!$data) {
            return null;
        }
        
        $product = new Product();
        $product->id = $data['id'];
        $product->name = $data['name'];
        $product->description = $data['description'];
        $product->price = (float)$data['price'];
        $product->stock = (int)$data['stock'];
        $product->created_at = new DateTime($data['created_at']);
        
        return $product;
    }
    
    public static function getAll(): array
    {
        $db = Database::getInstance()->getConnection();
        $sql = "SELECT * FROM products ORDER BY created_at DESC";
        $stmt = $db->query($sql);
        
        $products = [];
        while ($data = $stmt->fetch()) {
            $product = new Product();
            $product->id = $data['id'];
            $product->name = $data['name'];
            $product->description = $data['description'];
            $product->price = (float)$data['price'];
            $product->stock = (int)$data['stock'];
            $product->created_at = new DateTime($data['created_at']);
            
            $products[] = $product;
        }
        
        return $products;
    }
}
?>

2. 产品控制器

<?php
namespace AppControllers;

use AppModelsProduct;

class ProductController
{
    public function index(): void
    {
        $products = Product::getAll();
        
        // 在实际项目中,这里会渲染视图
        header('Content-Type: application/json');
        echo json_encode(array_map(function($product) {
            return [
                'id' => $product->id,
                'name' => $product->name,
                'price' => $product->price,
                'stock' => $product->stock
            ];
        }, $products));
    }
    
    public function show(int $id): void
    {
        $product = Product::find($id);
        
        if (!$product) {
            http_response_code(404);
            echo json_encode(['error' => '产品未找到']);
            return;
        }
        
        header('Content-Type: application/json');
        echo json_encode([
            'id' => $product->id,
            'name' => $product->name,
            'description' => $product->description,
            'price' => $product->price,
            'stock' => $product->stock
        ]);
    }
    
    public function create(): void
    {
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
            http_response_code(405);
            echo json_encode(['error' => '方法不允许']);
            return;
        }
        
        $data = json_decode(file_get_contents('php://input'), true);
        
        $product = new Product();
        $product->name = $data['name'] ?? '';
        $product->description = $data['description'] ?? '';
        $product->price = (float)($data['price'] ?? 0);
        $product->stock = (int)($data['stock'] ?? 0);
        
        if ($product->save()) {
            http_response_code(201);
            echo json_encode(['message' => '产品创建成功', 'id' => $product->id]);
        } else {
            http_response_code(500);
            echo json_encode(['error' => '产品创建失败']);
        }
    }
}
?>

PHP 8+ 高级特性应用

1. 枚举类型(PHP 8.1+)

<?php
namespace AppEnums;

enum OrderStatus: string
{
    case PENDING = 'pending';
    case PROCESSING = 'processing';
    case SHIPPED = 'shipped';
    case DELIVERED = 'delivered';
    case CANCELLED = 'cancelled';
    
    public function getLabel(): string
    {
        return match($this) {
            self::PENDING => '待处理',
            self::PROCESSING => '处理中',
            self::SHIPPED => '已发货',
            self::DELIVERED => '已送达',
            self::CANCELLED => '已取消'
        };
    }
    
    public function canBeCancelled(): bool
    {
        return in_array($this, [self::PENDING, self::PROCESSING]);
    }
}
?>

2. 属性构造器(PHP 8.0+)

<?php
namespace AppValueObjects;

class Money
{
    public function __construct(
        public readonly float $amount,
        public readonly string $currency = 'CNY'
    ) {
        if ($amount currency !== $other->currency) {
            throw new InvalidArgumentException('货币类型不匹配');
        }
        
        return new Money($this->amount + $other->amount, $this->currency);
    }
    
    public function format(): string
    {
        return number_format($this->amount, 2) . ' ' . $this->currency;
    }
}
?>

安全最佳实践

1. 输入验证器

<?php
namespace AppCore;

class Validator
{
    private array $errors = [];
    private array $data;
    
    public function __construct(array $data)
    {
        $this->data = $data;
    }
    
    public function required(string $field, string $message = '此字段为必填项'): self
    {
        if (!isset($this->data[$field]) || trim($this->data[$field]) === '') {
            $this->errors[$field][] = $message;
        }
        return $this;
    }
    
    public function email(string $field, string $message = '请输入有效的邮箱地址'): self
    {
        if (isset($this->data[$field]) && !filter_var($this->data[$field], FILTER_VALIDATE_EMAIL)) {
            $this->errors[$field][] = $message;
        }
        return $this;
    }
    
    public function minLength(string $field, int $length, string $message = '长度不足'): self
    {
        if (isset($this->data[$field]) && strlen($this->data[$field]) errors[$field][] = $message;
        }
        return $this;
    }
    
    public function passes(): bool
    {
        return empty($this->errors);
    }
    
    public function getErrors(): array
    {
        return $this->errors;
    }
}
?>

2. 中间件:认证保护

<?php
namespace AppMiddlewares;

class AuthMiddleware
{
    public function handle(): bool
    {
        session_start();
        
        if (!isset($_SESSION['user_id'])) {
            http_response_code(401);
            echo json_encode(['error' => '未授权访问']);
            return false;
        }
        
        return true;
    }
}
?>

3. 应用入口点(public/index.php)

<?php
require_once __DIR__ . '/../vendor/autoload.php';

use AppCoreRouter;
use AppControllersProductController;
use AppMiddlewaresAuthMiddleware;

$router = new Router();

// 公开路由
$router->add('GET', '/products', [ProductController::class, 'index']);
$router->add('GET', '/products/{id}', [ProductController::class, 'show']);

// 需要认证的路由
$router->middleware(AuthMiddleware::class)
       ->add('POST', '/products', [ProductController::class, 'create']);

$method = $_SERVER['REQUEST_METHOD'];
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);

$router->dispatch($method, $path);
?>

总结与进阶方向

本教程实现的核心功能:

  • 完整的MVC架构实现
  • 面向对象的数据库操作层
  • 灵活的路由系统
  • 输入验证和安全防护
  • PHP 8+ 新特性应用

后续学习建议:

  1. 集成模板引擎(Twig/Blade)
  2. 实现RESTful API设计
  3. 添加单元测试和集成测试
  4. 研究设计模式在PHP中的应用
  5. 学习性能优化和缓存策略

架构思维:现代PHP开发不仅仅是写代码,更是构建可维护、可扩展、安全的系统架构。通过本教程的学习,你已经掌握了构建企业级应用的核心技能。

PHP面向对象编程实战:构建MVC电商系统架构 | 后端开发教程
收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

淘吗网 php PHP面向对象编程实战:构建MVC电商系统架构 | 后端开发教程 https://www.taomawang.com/server/php/1176.html

常见问题

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务