如何在PHP项目中保持整洁:无痛的六边形架构

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

当您的PHP单体应用开始出现裂痕时

\n

您是否曾遇到过这样的情况:将数据库从MySQL切换到PostgreSQL变成了一场为期一周的探索?或者当您需要添加一个新的API客户端,而代码与框架紧密耦合,以至于从头开始编写反而更简单?熟悉吗?

\n

大多数PHP开发者迟早会在控制器和模型中遇到“意大利面条式代码”。像Laravel或Symfony这样的框架提供了便捷的工具,但它们也强制了与自身的紧密绑定。解决方案是——六边形架构(也称为“端口与适配器”或六边形架构)。

\n

在本文中,我们将探讨如何构建一个不依赖于框架、数据库或外部服务的PHP应用。您将看到可以直接在项目中应用的代码示例。让我们开始吧!

\n\n

什么是六边形架构,为什么您需要它?

\n

想象一个六边形。中心是您的业务逻辑(领域)。周围是“端口”(接口),外部世界通过这些端口与核心通信。外部是“适配器”,它们实现这些端口:控制器、仓库、API客户端。

\n

核心理念:应用核心对外部世界一无所知。它不导入Laravel,不了解PDO,也不调用curl。所有依赖关系都指向内部——适配器依赖于端口,而不是相反。

\n

这种方法的优点显而易见:

\n
    \n
  • 可测试性:无需数据库和HTTP请求即可测试业务逻辑。
  • \n
  • 灵活性:更换数据库、队列或框架只需编写一个新的适配器。
  • \n
  • 代码纯净:您不会将“做什么”与“怎么做”混为一谈。
  • \n
\n

听起来像魔法?让我们看看代码。

\n\n

项目结构:基本骨架

\n

我们以一个简单的场景为例:用户注册。我们需要将用户保存到数据库并发送欢迎邮件。

\n

典型的目录结构如下:

\n
src/\n├── Domain/\n│   ├── Entity/\n│   │   └── User.php\n│   ├── Repository/\n│   │   └── UserRepositoryInterface.php\n│   ├── Service/\n│   │   └── UserRegistrationService.php\n│   └── Event/\n│       └── UserRegisteredEvent.php\n├── Infrastructure/\n│   ├── Persistence/\n│   │   └── DoctrineUserRepository.php\n│   ├── Mail/\n│   │   └── SymfonyMailerAdapter.php\n│   └── Controller/\n│       └── RegisterUserController.php\n└── Application/\n    └── UseCase/\n        └── RegisterUserUseCase.php
\n

请注意:Domain是纯净的业务逻辑。Infrastructure是适配器。Application是用例。

\n\n

步骤1:核心——领域与端口

\n

实体(Entity)

\n

我们从最简单的开始——用户。这只是一个包含数据的类,没有依赖关系。

\n
<?php\nnamespace App\\Domain\\Entity;\n\nclass User\n{\n    public function __construct(\n        private readonly string $id,\n        private string $name,\n        private string $email\n    ) {}\n\n    public function getId(): string\n    {\n        return $this->id;\n    }\n\n    public function getName(): string\n    {\n        return $this->name;\n    }\n\n    public function getEmail(): string\n    {\n        return $this->email;\n    }\n}
\n\n

端口——仓库接口

\n

现在定义我们将如何保存用户。这是一个端口——将由适配器实现的接口。

\n
<?php\nnamespace App\\Domain\\Repository;\n\nuse App\\Domain\\Entity\\User;\n\ninterface UserRepositoryInterface\n{\n    public function save(User $user): void;\n    public function findByEmail(string $email): ?User;\n}
\n\n

端口——邮件服务接口

\n

类似地,用于发送邮件:

\n
<?php\nnamespace App\\Domain\\Service;\n\nuse App\\                

博客

书籍推荐