php方案 洋葱架构
│ Infrastructure │ 技术实现│ Domain + Application│ MySQLOrderRepository, StripePayment │。│ Domain│ 核心业务逻辑 │ 无(或只依赖其他领域对象) │ Order, Money, OrderRepository(接口) │。// 需要改成 $this->mongoDB->insert(…│MySQL/Redis
6. 洋葱架构
6.1 层次结构
┌─────────────────────────────────────┐
│ Infrastructure Layer │ ← 框架、ORM、外部依赖
│ ┌───────────────────────────────┐ │
│ │ Application Layer │ │ ← 用例、应用服务
│ │ ┌─────────────────────────┐ │ │
│ │ │ Domain Layer │ │ │ ← 领域模型、业务规则
│ │ │ ┌───────────────────┐ │ │ │
│ │ │ │ Domain Model │ │ │ │ ← 实体、值对象
│ │ │ └───────────────────┘ │ │ │
│ │ └─────────────────────────┘ │ │
│ └───────────────────────────────┘ │
└─────────────────────────────────────┘
6.2 依赖规则
- 核心原则: 依赖只能从外层指向内层
- Domain Layer: 不依赖任何外部层
- Application Layer: 只依赖 Domain Layer
- Infrastructure Layer: 实现内层定义的接口
<?php
// ✅ 正确:Infrastructure 依赖 Domain
namespace Infrastructure;
use Domain\OrderRepository; // 依赖接口
class MySQLOrderRepository implements OrderRepository {
// 实现细节
}
// ❌ 错误:Domain 依赖 Infrastructure
namespace Domain;
use Infrastructure\MySQLConnection; // 违反依赖规则
class Order {
private MySQLConnection $db; // 不应直接依赖基础设施
}
依赖规则(Dependency Rule),是 DDD 和整洁架构的核心原则。核心思想如下:
核心理念
依赖方向只能从外向内,内层定义接口(契约),外层实现接口。业务核心(领域层)不依赖任何技术细节。
分层依赖方向
┌─────────────────────────────────────────────┐
│ Infrastructure Layer (基础设施层) │
│ MySQL/Redis/HTTP/Email (技术实现) │
│ ↓ 依赖 (implements) │
├─────────────────────────────────────────────┤
│ Application Layer (应用层) │
│ Use Cases / Application Services │
│ ↓ 依赖 (uses) │
├─────────────────────────────────────────────┤
│ Domain Layer (领域层) ← 核心! │
│ 实体/值对象/领域服务/接口定义 │
│ (不依赖任何外层!) │
└─────────────────────────────────────────────┘
依赖方向:Infrastructure → Application → Domain
外层 中层 内层
关键规则
✅ 正确:外层依赖内层
// Infrastructure 层(外层)
namespace Infrastructure;
use Domain\OrderRepository; // ✅ 依赖领域层的接口
class MySQLOrderRepository implements OrderRepository {
public function save(Order $order): void {
// 使用 MySQL 实现
$this->pdo->execute(‘INSERT INTO orders …’);
}
}
❌ 错误:内层依赖外层
// Domain 层(内层)
namespace Domain;
use Infrastructure\MySQLConnection; // ❌ 违反依赖规则!
class Order {
private MySQLConnection $db; // ❌ 领域层不应知道 MySQL 的存在
public function save(): void {
$this->db->execute('INSERT ...'); // ❌ 领域逻辑耦合数据库
}
}
依赖倒置原则(DIP)
高层模块不依赖低层模块,两者都依赖抽象(接口)。
传统方式(违反依赖规则)
// 业务逻辑直接依赖技术实现
class OrderService {
private MySQLDatabase $db; // ❌ 直接依赖具体实现
public function createOrder(Order $order): void {
$this->db->insert('orders', $order->toArray());
}
}
// 问题:
// 1. 无法切换数据库(强耦合 MySQL)
// 2. 无法测试(必须连接真实数据库)
// 3. 业务逻辑依赖技术细节
DDD 方式(遵循依赖规则)
// 领域层:定义接口(抽象)
namespace Domain;
interface OrderRepository {
public function save(Order $order): void;
public function findById(OrderId $id): ?Order;
}
// 应用层:依赖接口
namespace Application;
use Domain\OrderRepository; // ✅ 依赖抽象
class CreateOrderUseCase {
public function __construct(
private OrderRepository $orderRepo // ✅ 依赖接口,不是实现
) {}
public function execute(CreateOrderRequest $request): void {
$order = Order::create(...);
$this->orderRepo->save($order); // 不知道具体是 MySQL/Mongo
}
}
// 基础设施层:实现接口
namespace Infrastructure;
use Domain\OrderRepository; // ✅ 依赖领域层接口
class MySQLOrderRepository implements OrderRepository {
public function save(Order $order): void {
// MySQL 实现细节
}
}
依赖注入(连接各层)
// 在入口文件(Composition Root)组装依赖
$pdo = new PDO(‘mysql:…’);
orderRepo=newMySQLOrderRepository(orderRepo = new MySQLOrderRepository(orderRepo=newMySQLOrderRepository(pdo); // 具体实现
useCase=newCreateOrderUseCase(useCase = new CreateOrderUseCase(useCase=newCreateOrderUseCase(orderRepo); // 注入接口
controller=newOrderController(controller = new OrderController(controller=newOrderController(useCase);
// 业务代码中永远不知道具体实现!
分层职责和依赖
┌────────────────┬──────────────┬────────────────────────────┬─────────────────────────────────────┐
│ 层级 │ 职责 │ 依赖 │ 示例 │
├────────────────┼──────────────┼────────────────────────────┼─────────────────────────────────────┤
│ Domain │ 核心业务逻辑 │ 无(或只依赖其他领域对象) │ Order, Money, OrderRepository(接口) │
├────────────────┼──────────────┼────────────────────────────┼─────────────────────────────────────┤
│ Application │ 编排业务流程 │ Domain 层 │ CreateOrderUseCase │
├────────────────┼──────────────┼────────────────────────────┼─────────────────────────────────────┤
│ Infrastructure │ 技术实现 │ Domain + Application │ MySQLOrderRepository, StripePayment │
├────────────────┼──────────────┼────────────────────────────┼─────────────────────────────────────┤
│ Presentation │ 用户界面 │ Application 层 │ OrderController, CLI │
└────────────────┴──────────────┴────────────────────────────┴─────────────────────────────────────┘
为什么要这样设计?
- 业务逻辑稳定,技术可变
// 场景:从 MySQL 切换到 MongoDB
// ❌ 传统方式:业务代码大量修改
class Order {
public function save(): void {
$this->mysqlDb->insert(…); // 需要改成 $this->mongoDB->insert(…)
}
}
// ✅ DDD 方式:只需更换实现
$orderRepo = new MongoOrderRepository(); // 替换实现
useCase=newCreateOrderUseCase(useCase = new CreateOrderUseCase(useCase=newCreateOrderUseCase(orderRepo); // 业务代码不变!
- 易于测试
// 测试时使用内存实现,不需要真实数据库
class InMemoryOrderRepository implements OrderRepository {
private array $orders = [];
public function save(Order $order): void {
$this->orders[] = $order;
}
}
// 测试 Use Case
$useCase = new CreateOrderUseCase(new InMemoryOrderRepository());
useCase−>execute(useCase->execute(useCase−>execute(request); // 无需启动 MySQL!
- 业务逻辑独立演进
// 领域层修改业务规则,不影响基础设施
class Order {
public function addItem(OrderItem KaTeX parse error: Expected '}', got 'EOF' at end of input: … if (this->items->count() >= 100) {
throw new TooManyItemsException();
}
this−>items−>add(this->items->add(this−>items−>add(item);
}
}
// Infrastructure 层代码无需修改!
实际示例对比
❌ 违反依赖规则
namespace Domain;
use Illuminate\Database\Eloquent\Model; // ❌ 依赖框架
class Order extends Model { // ❌ 领域对象继承 ORM
protected $table = ‘orders’; // ❌ 领域层知道数据库表名
public function complete(): void {
$this->status = 'completed';
$this->save(); // ❌ 领域逻辑直接保存到数据库
}
}
问题:
- 领域层依赖 Laravel 框架(无法脱离框架运行)
- 业务逻辑和持久化混在一起
- 无法切换 ORM 或数据库
- 测试需要真实数据库
✅ 遵循依赖规则
// Domain 层:纯业务逻辑
namespace Domain;
class Order { // ✅ 纯 PHP 对象,无外部依赖
private OrderId $orderId;
private OrderStatus $status;
private array $domainEvents = [];
public function complete(): void {
if (!$this->canBeCompleted()) {
throw new CannotCompleteOrderException();
}
$this->status = OrderStatus::COMPLETED;
$this->domainEvents[] = new OrderCompletedEvent($this->orderId);
}
}
// Domain 层:定义接口
interface OrderRepository {
public function save(Order $order): void;
}
// Infrastructure 层:实现接口
namespace Infrastructure;
class EloquentOrderRepository implements OrderRepository {
public function save(Order $order): void {
// 使用 Eloquent 持久化
OrderModel::updateOrCreate([
‘order_id’ => $order->getId()->toString(),
], [
‘status’ => $order->getStatus()->getValue(),
]);
}
}
优势:
- Domain 层可以独立测试(无需框架)
- 可以切换到 Doctrine/原生 SQL
- 业务逻辑清晰、可复用
依赖流向图
┌────────────────────────────────────────┐
│ OrderController (Presentation) │
│ 依赖 ↓ │
├────────────────────────────────────────┤
│ CreateOrderUseCase (Application) │
│ 依赖 ↓ │
├────────────────────────────────────────┤
│ Order (Domain) │
│ OrderRepository (接口定义在 Domain) │
│ ↑ 实现 │
├────────────────────────────────────────┤
│ MySQLOrderRepository (Infrastructure) │
│ (依赖 Domain 层的接口) │
└────────────────────────────────────────┘
总结
┌──────────┬────────────────────┬──────────────────┐
│ 方面 │ 依赖规则要求 │ 好处 │
├──────────┼────────────────────┼──────────────────┤
│ 依赖方向 │ 外层 → 内层 │ 业务核心稳定 │
├──────────┼────────────────────┼──────────────────┤
│ 接口定义 │ 内层定义,外层实现 │ 依赖倒置 │
├──────────┼────────────────────┼──────────────────┤
│ 领域层 │ 不依赖任何外层 │ 可独立测试、迁移 │
├──────────┼────────────────────┼──────────────────┤
│ 基础设施 │ 实现领域层接口 │ 技术可替换 │
└──────────┴────────────────────┴──────────────────┘
核心:业务逻辑(Domain)是系统的心脏,技术实现(Infrastructure)是可替换的器官。通过接口(抽象)连接,实现业务与技术的解耦。
更多推荐

所有评论(0)