本文目录导读:

我来详细讲解PHP洋葱架构(Onion Architecture)的概念和实现方法。
什么是洋葱架构
洋葱架构是一种分层架构模式,强调依赖方向始终向内层,核心业务逻辑不依赖外部基础设施。
外层:基础设施(数据库、框架、外部API)
↓
应用层:用例、应用服务
↓
领域层:实体、值对象、领域服务
↓
核心:领域模型(最内层)
PHP实现示例
目录结构
src/
├── Domain/ # 领域层(最内层)
│ ├── Entity/ # 实体
│ ├── ValueObject/ # 值对象
│ ├── Repository/ # 仓库接口
│ └── Service/ # 领域服务
├── Application/ # 应用层
│ ├── UseCase/ # 用例
│ └── DTO/ # 数据传输对象
├── Infrastructure/ # 基础设施层(最外层)
│ ├── Persistence/ # 持久化
│ ├── Framework/ # 框架适配
│ └── External/ # 外部服务
└── Interface/ # 接口层
├── Controller/ # 控制器
└── Request/ # 请求处理
领域层实现
<?php
// Domain/Entity/User.php
namespace App\Domain\Entity;
class User
{
private string $id;
private string $name;
private Email $email;
public function __construct(string $id, string $name, Email $email)
{
$this->id = $id;
$this->name = $name;
$this->email = $email;
}
public function getId(): string
{
return $this->id;
}
public function getName(): string
{
return $this->name;
}
public function getEmail(): Email
{
return $this->email;
}
}
// Domain/ValueObject/Email.php
namespace App\Domain\ValueObject;
class Email
{
private string $value;
public function __construct(string $value)
{
if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
throw new \InvalidArgumentException('Invalid email address');
}
$this->value = $value;
}
public function getValue(): string
{
return $this->value;
}
}
// Domain/Repository/UserRepositoryInterface.php
namespace App\Domain\Repository;
use App\Domain\Entity\User;
interface UserRepositoryInterface
{
public function findById(string $id): ?User;
public function save(User $user): void;
public function delete(string $id): void;
}
应用层实现
<?php
// Application/UseCase/CreateUserUseCase.php
namespace App\Application\UseCase;
use App\Domain\Entity\User;
use App\Domain\Repository\UserRepositoryInterface;
use App\Domain\ValueObject\Email;
use App\Application\DTO\CreateUserRequest;
use App\Application\DTO\CreateUserResponse;
class CreateUserUseCase
{
public function __construct(
private UserRepositoryInterface $userRepository
) {}
public function execute(CreateUserRequest $request): CreateUserResponse
{
// 业务逻辑校验
$email = new Email($request->getEmail());
$existingUser = $this->userRepository->findById($request->getId());
if ($existingUser) {
throw new \RuntimeException('User already exists');
}
// 创建用户
$user = new User(
$request->getId(),
$request->getName(),
$email
);
// 保存用户
$this->userRepository->save($user);
return new CreateUserResponse(
$user->getId(),
$user->getName()
);
}
}
// Application/DTO/CreateUserRequest.php
namespace App\Application\DTO;
class CreateUserRequest
{
public function __construct(
private string $id,
private string $name,
private string $email
) {}
public function getId(): string
{
return $this->id;
}
public function getName(): string
{
return $this->name;
}
public function getEmail(): string
{
return $this->email;
}
}
// Application/DTO/CreateUserResponse.php
namespace App\Application\DTO;
class CreateUserResponse
{
public function __construct(
private string $id,
private string $name
) {}
public function getId(): string
{
return $this->id;
}
public function getName(): string
{
return $this->name;
}
}
基础设施层实现
<?php
// Infrastructure/Persistence/UserRepository.php
namespace App\Infrastructure\Persistence;
use App\Domain\Entity\User;
use App\Domain\Repository\UserRepositoryInterface;
use App\Domain\ValueObject\Email;
use PDO;
class UserRepository implements UserRepositoryInterface
{
private PDO $connection;
public function __construct(PDO $connection)
{
$this->connection = $connection;
}
public function findById(string $id): ?User
{
$stmt = $this->connection->prepare('SELECT * FROM users WHERE id = ?');
$stmt->execute([$id]);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$row) {
return null;
}
return new User(
$row['id'],
$row['name'],
new Email($row['email'])
);
}
public function save(User $user): void
{
$stmt = $this->connection->prepare(
'INSERT INTO users (id, name, email) VALUES (?, ?, ?)
ON DUPLICATE KEY UPDATE name = VALUES(name), email = VALUES(email)'
);
$stmt->execute([
$user->getId(),
$user->getName(),
$user->getEmail()->getValue()
]);
}
public function delete(string $id): void
{
$stmt = $this->connection->prepare('DELETE FROM users WHERE id = ?');
$stmt->execute([$id]);
}
}
接口层实现(Controller)
<?php
// Interface/Controller/UserController.php
namespace App\Interface\Controller;
use App\Application\DTO\CreateUserRequest;
use App\Application\UseCase\CreateUserUseCase;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class UserController
{
public function __construct(
private CreateUserUseCase $createUserUseCase
) {}
public function create(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
{
try {
$body = json_decode($request->getBody()->getContents(), true);
$createUserRequest = new CreateUserRequest(
$body['id'] ?? uniqid(),
$body['name'],
$body['email']
);
$result = $this->createUserUseCase->execute($createUserRequest);
$response->getBody()->write(json_encode([
'success' => true,
'data' => [
'id' => $result->getId(),
'name' => $result->getName()
]
]));
return $response->withStatus(201);
} catch (\Exception $e) {
$response->getBody()->write(json_encode([
'success' => false,
'error' => $e->getMessage()
]));
return $response->withStatus(400);
}
}
}
应用容器配置
<?php
// config/container.php
use App\Domain\Repository\UserRepositoryInterface;
use App\Infrastructure\Persistence\UserRepository;
use App\Application\UseCase\CreateUserUseCase;
use App\Interface\Controller\UserController;
return [
'dependencies' => [
'definitions' => [
PDO::class => function() {
return new PDO('mysql:host=localhost;dbname=test', 'user', 'password');
},
UserRepositoryInterface::class => function($container) {
return new UserRepository($container->get(PDO::class));
},
CreateUserUseCase::class => function($container) {
return new CreateUserUseCase(
$container->get(UserRepositoryInterface::class)
);
},
UserController::class => function($container) {
return new UserController(
$container->get(CreateUserUseCase::class)
);
}
]
]
];
路由配置
<?php
// routes.php
use App\Interface\Controller\UserController;
$app->post('/users', [UserController::class, 'create']);
$app->get('/users/{id}', [UserController::class, 'get']);
$app->put('/users/{id}', [UserController::class, 'update']);
$app->delete('/users/{id}', [UserController::class, 'delete']);
核心原则
依赖规则
- 内层不依赖外层
- 依赖方向始终向内
- 通过接口实现依赖倒置
领域模型
- 核心业务逻辑
- 不含技术细节
- 业务规则表达
应用服务
- 用例执行
- 事务管理
- 事件发布
基础设施
- 数据库实现
- 框架集成
- 外部服务
最佳实践
<?php
// 高级示例:依赖注入
// UseCase with dependency inversion
class OrderService
{
public function __construct(
private OrderRepositoryInterface $orderRepository,
private PaymentGatewayInterface $paymentGateway,
private EventDispatcherInterface $eventDispatcher
) {}
public function processOrder(Order $order): void
{
// 业务逻辑
$order->markAsProcessing();
$this->orderRepository->save($order);
// 外部依赖
$paymentResult = $this->paymentGateway->process(
$order->getTotal()
);
// 领域事件
$this->eventDispatcher->dispatch(
new OrderProcessedEvent($order)
);
}
}
优点
- 清晰分层:职责明确
- 可测试性:核心逻辑不依赖外部
- 可维护性:易扩展和修改
- 解耦:基础设施变更影响小
- 业务焦点:核心关注业务规则
注意事项
- 避免过设计:简单项目不需要全架构
- 严格控制依赖方向:不要反向依赖
- 接口设计合理:不要过多或过少
- 性能考虑:多层可能影响性能
- 学习成本:团队需要理解架构
洋葱架构适合:
- 复杂业务系统
- 需要长期维护的项目
- 团队有DDD经验
- 需要高度可测试性
通过这种方式,你可以构建一个清晰、可维护、可扩展的PHP应用架构。