本文目录导读:

我来给你展示一个完整的PHP DDD(领域驱动设计)示例,这里以一个简单的订单系统为例:
领域层(Domain Layer)
值对象(Value Objects)
<?php
// Domain/ValueObject/Money.php
namespace App\Domain\ValueObject;
class Money
{
private float $amount;
private string $currency;
public function __construct(float $amount, string $currency = 'CNY')
{
if ($amount < 0) {
throw new \InvalidArgumentException('金额不能为负数');
}
$this->amount = $amount;
$this->currency = $currency;
}
public function getAmount(): float
{
return $this->amount;
}
public function getCurrency(): string
{
return $this->currency;
}
public function add(Money $money): Money
{
if ($this->currency !== $money->currency) {
throw new \InvalidArgumentException('货币不一致');
}
return new Money($this->amount + $money->amount, $this->currency);
}
public function equals(Money $money): bool
{
return $this->amount === $money->amount
&& $this->currency === $money->currency;
}
}
实体(Entities)
<?php
// Domain/Entity/Order.php
namespace App\Domain\Entity;
use App\Domain\ValueObject\Money;
use App\Domain\ValueObject\OrderStatus;
class Order
{
private string $id;
private string $customerId;
private array $items = [];
private Money $totalAmount;
private OrderStatus $status;
private \DateTimeImmutable $createdAt;
private ?\DateTimeImmutable $paidAt = null;
public function __construct(string $id, string $customerId)
{
$this->id = $id;
$this->customerId = $customerId;
$this->totalAmount = new Money(0);
$this->status = new OrderStatus(OrderStatus::PENDING);
$this->createdAt = new \DateTimeImmutable();
}
public function addItem(OrderItem $item): void
{
$this->items[] = $item;
$this->recalculateTotal();
}
public function removeItem(string $itemId): void
{
$this->items = array_filter(
$this->items,
fn(OrderItem $item) => $item->getId() !== $itemId
);
$this->recalculateTotal();
}
public function pay(): void
{
if ($this->status->getValue() !== OrderStatus::PENDING) {
throw new \DomainException('只有待支付订单才能支付');
}
if ($this->totalAmount->getAmount() <= 0) {
throw new \DomainException('订单金额必须大于0');
}
$this->status = new OrderStatus(OrderStatus::PAID);
$this->paidAt = new \DateTimeImmutable();
}
public function cancel(): void
{
if (!in_array($this->status->getValue(), [OrderStatus::PENDING, OrderStatus::PAID])) {
throw new \DomainException('当前状态不能取消');
}
$this->status = new OrderStatus(OrderStatus::CANCELLED);
}
private function recalculateTotal(): void
{
$total = new Money(0);
foreach ($this->items as $item) {
$total = $total->add($item->getSubtotal());
}
$this->totalAmount = $total;
}
// Getters...
public function getId(): string { return $this->id; }
public function getCustomerId(): string { return $this->customerId; }
public function getItems(): array { return $this->items; }
public function getTotalAmount(): Money { return $this->totalAmount; }
public function getStatus(): OrderStatus { return $this->status; }
public function getCreatedAt(): \DateTimeImmutable { return $this->createdAt; }
public function getPaidAt(): ?\DateTimeImmutable { return $this->paidAt; }
}
<?php
// Domain/Entity/OrderItem.php
namespace App\Domain\Entity;
use App\Domain\ValueObject\Money;
class OrderItem
{
private string $id;
private string $productId;
private string $productName;
private Money $price;
private int $quantity;
public function __construct(
string $id,
string $productId,
string $productName,
Money $price,
int $quantity
) {
$this->id = $id;
$this->productId = $productId;
$this->productName = $productName;
$this->price = $price;
$this->quantity = $quantity;
}
public function getSubtotal(): Money
{
return new Money($this->price->getAmount() * $this->quantity);
}
// Getters...
public function getId(): string { return $this->id; }
public function getProductId(): string { return $this->productId; }
public function getProductName(): string { return $this->productName; }
public function getPrice(): Money { return $this->price; }
public function getQuantity(): int { return $this->quantity; }
}
值对象 - 订单状态
<?php
// Domain/ValueObject/OrderStatus.php
namespace App\Domain\ValueObject;
class OrderStatus
{
public const PENDING = 'pending';
public const PAID = 'paid';
public const SHIPPED = 'shipped';
public const CANCELLED = 'cancelled';
private string $value;
private const VALID_STATUSES = [
self::PENDING,
self::PAID,
self::SHIPPED,
self::CANCELLED,
];
public function __construct(string $value)
{
if (!in_array($value, self::VALID_STATUSES)) {
throw new \InvalidArgumentException('无效的订单状态');
}
$this->value = $value;
}
public function getValue(): string
{
return $this->value;
}
public function equals(OrderStatus $status): bool
{
return $this->value === $status->getValue();
}
}
领域服务(Domain Services)
<?php
// Domain/Service/OrderPricingService.php
namespace App\Domain\Service;
use App\Domain\Entity\Order;
use App\Domain\ValueObject\Money;
class OrderPricingService
{
private const DISCOUNT_THRESHOLD = 1000;
private const DISCOUNT_RATE = 0.1; // 10% discount
public function applyDiscount(Order $order): Money
{
$total = $order->getTotalAmount();
if ($total->getAmount() >= self::DISCOUNT_THRESHOLD) {
$discountedAmount = $total->getAmount() * (1 - self::DISCOUNT_RATE);
return new Money($discountedAmount);
}
return $total;
}
}
应用层(Application Layer)
应用服务(Application Services)
<?php
// Application/Service/OrderService.php
namespace App\Application\Service;
use App\Domain\Entity\Order;
use App\Domain\Entity\OrderItem;
use App\Domain\Repository\OrderRepositoryInterface;
use App\Domain\Repository\UserRepositoryInterface;
use App\Domain\ValueObject\Money;
use App\Application\DTO\CreateOrderRequest;
use App\Application\DTO\OrderResponse;
class OrderService
{
private OrderRepositoryInterface $orderRepository;
private UserRepositoryInterface $userRepository;
public function __construct(
OrderRepositoryInterface $orderRepository,
UserRepositoryInterface $userRepository
) {
$this->orderRepository = $orderRepository;
$this->userRepository = $userRepository;
}
public function createOrder(CreateOrderRequest $request): OrderResponse
{
// 验证用户
$user = $this->userRepository->findById($request->customerId);
if (!$user) {
throw new \DomainException('用户不存在');
}
// 创建订单实体
$order = new Order(
uniqid('order_', true),
$request->customerId
);
// 添加订单项
foreach ($request->items as $item) {
$order->addItem(
new OrderItem(
uniqid('item_', true),
$item['productId'],
$item['productName'],
new Money($item['price']),
$item['quantity']
)
);
}
// 保存订单
$this->orderRepository->save($order);
return OrderResponse::fromEntity($order);
}
public function getOrder(string $orderId): OrderResponse
{
$order = $this->orderRepository->findById($orderId);
if (!$order) {
throw new \DomainException('订单不存在');
}
return OrderResponse::fromEntity($order);
}
public function payOrder(string $orderId): OrderResponse
{
$order = $this->orderRepository->findById($orderId);
if (!$order) {
throw new \DomainException('订单不存在');
}
$order->pay();
$this->orderRepository->save($order);
return OrderResponse::fromEntity($order);
}
}
DTOs(数据传输对象)
<?php
// Application/DTO/CreateOrderRequest.php
namespace App\Application\DTO;
class CreateOrderRequest
{
public string $customerId;
public array $items;
public function __construct(string $customerId, array $items)
{
$this->customerId = $customerId;
$this->items = $items;
}
}
<?php
// Application/DTO/OrderResponse.php
namespace App\Application\DTO;
use App\Domain\Entity\Order;
use App\Domain\Entity\OrderItem;
class OrderResponse
{
public string $id;
public string $customerId;
public array $items;
public float $totalAmount;
public string $status;
public string $createdAt;
public static function fromEntity(Order $order): self
{
$response = new self();
$response->id = $order->getId();
$response->customerId = $order->getCustomerId();
$response->items = array_map(
fn(OrderItem $item) => [
'id' => $item->getId(),
'productId' => $item->getProductId(),
'productName' => $item->getProductName(),
'price' => $item->getPrice()->getAmount(),
'quantity' => $item->getQuantity(),
'subtotal' => $item->getSubtotal()->getAmount()
],
$order->getItems()
);
$response->totalAmount = $order->getTotalAmount()->getAmount();
$response->status = $order->getStatus()->getValue();
$response->createdAt = $order->getCreatedAt()->format('Y-m-d H:i:s');
return $response;
}
}
基础设施层(Infrastructure Layer)
仓储实现
<?php
// Infrastructure/Repository/InMemoryOrderRepository.php
namespace App\Infrastructure\Repository;
use App\Domain\Entity\Order;
use App\Domain\Repository\OrderRepositoryInterface;
class InMemoryOrderRepository implements OrderRepositoryInterface
{
private array $orders = [];
public function save(Order $order): void
{
$this->orders[$order->getId()] = $order;
}
public function findById(string $id): ?Order
{
return $this->orders[$id] ?? null;
}
public function delete(string $id): void
{
unset($this->orders[$id]);
}
public function findAll(): array
{
return array_values($this->orders);
}
}
仓储接口
<?php
// Domain/Repository/OrderRepositoryInterface.php
namespace App\Domain\Repository;
use App\Domain\Entity\Order;
interface OrderRepositoryInterface
{
public function save(Order $order): void;
public function findById(string $id): ?Order;
public function delete(string $id): void;
public function findAll(): array;
}
使用示例
<?php
// index.php 或 Controller
use App\Application\Service\OrderService;
use App\Application\DTO\CreateOrderRequest;
use App\Infrastructure\Repository\InMemoryOrderRepository;
use App\Infrastructure\Repository\InMemoryUserRepository;
// 依赖注入设置
$orderRepository = new InMemoryOrderRepository();
$userRepository = new InMemoryUserRepository();
$orderService = new OrderService($orderRepository, $userRepository);
// 创建订单
$request = new CreateOrderRequest('user123', [
[
'productId' => 'prod1',
'productName' => 'iPhone',
'price' => 5000,
'quantity' => 1
],
[
'productId' => 'prod2',
'productName' => 'AirPods',
'price' => 1500,
'quantity' => 2
]
]);
try {
$orderResponse = $orderService->createOrder($request);
echo "订单创建成功: " . $orderResponse->id . "\n";
echo "总金额: " . $orderResponse->totalAmount . "\n";
// 支付订单
$orderResponse = $orderService->payOrder($orderResponse->id);
echo "订单支付成功,状态: " . $orderResponse->status . "\n";
} catch (\Exception $e) {
echo "错误: " . $e->getMessage() . "\n";
}
目录结构
project/
├── src/
│ ├── Domain/
│ │ ├── Entity/
│ │ │ ├── Order.php
│ │ │ └── OrderItem.php
│ │ ├── ValueObject/
│ │ │ ├── Money.php
│ │ │ └── OrderStatus.php
│ │ ├── Service/
│ │ │ └── OrderPricingService.php
│ │ └── Repository/
│ │ ├── OrderRepositoryInterface.php
│ │ └── UserRepositoryInterface.php
│ ├── Application/
│ │ ├── Service/
│ │ │ └── OrderService.php
│ │ └── DTO/
│ │ ├── CreateOrderRequest.php
│ │ └── OrderResponse.php
│ └── Infrastructure/
│ ├── Repository/
│ │ ├── InMemoryOrderRepository.php
│ │ └── InMemoryUserRepository.php
│ └── Database/
│ └── (数据库相关类)
└── index.php
这个示例展示了DDD的核心概念:
- 值对象:Money、OrderStatus
- 实体:Order、OrderItem
- 领域服务:OrderPricingService
- 应用服务:OrderService
- 仓储接口与实现:OrderRepositoryInterface
- DTO:CreateOrderRequest、OrderResponse