PHP 怎么PHP洋葱架构

wen PHP项目 1

本文目录导读:

PHP 怎么PHP洋葱架构

  1. 什么是洋葱架构
  2. PHP实现示例
  3. 核心原则
  4. 最佳实践
  5. 优点
  6. 注意事项

我来详细讲解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)
        );
    }
}

优点

  1. 清晰分层:职责明确
  2. 可测试性:核心逻辑不依赖外部
  3. 可维护性:易扩展和修改
  4. 解耦:基础设施变更影响小
  5. 业务焦点:核心关注业务规则

注意事项

  1. 避免过设计:简单项目不需要全架构
  2. 严格控制依赖方向:不要反向依赖
  3. 接口设计合理:不要过多或过少
  4. 性能考虑:多层可能影响性能
  5. 学习成本:团队需要理解架构

洋葱架构适合:

  • 复杂业务系统
  • 需要长期维护的项目
  • 团队有DDD经验
  • 需要高度可测试性

通过这种方式,你可以构建一个清晰、可维护、可扩展的PHP应用架构。

抱歉,评论功能暂时关闭!