本文目录导读:

我将为你详细讲解PHP整洁架构(Clean Architecture)的实现方法,整洁架构是由Robert C. Martin(Uncle Bob)提出的,核心思想是依赖向内,外层依赖内层。
🏗️ 整洁架构的核心结构
graph TD
A[框架/UI层] --> B[适配器层]
B --> C[用例层]
C --> D[实体层]
D -.->|依赖倒置| C
C -.->|依赖倒置| B
目录结构示例
src/
├── Domain/ # 实体层(最内层)
│ ├── Entities/ # 核心业务实体
│ ├── ValueObjects/ # 值对象
│ └── Repositories/ # 仓储接口
├── Application/ # 用例层
│ ├── UseCases/ # 具体业务用例
│ ├── DTOs/ # 数据传输对象
│ └── Ports/ # 接口定义
├── Infrastructure/ # 适配器层
│ ├── Persistence/ # 数据库实现
│ ├── HTTP/ # HTTP客户端
│ └── Messaging/ # 消息队列
└── Presentation/ # 框架/UI层
├── Controllers/ # 控制器
├── Middleware/ # 中间件
└── Views/ # 视图
📦 完整实现示例
Domain层(实体层)
<?php
// src/Domain/Entities/User.php
namespace App\Domain\Entities;
use App\Domain\ValueObjects\Email;
use App\Domain\ValueObjects\UserId;
class User
{
private UserId $id;
private string $name;
private Email $email;
private \DateTimeImmutable $createdAt;
public function __construct(UserId $id, string $name, Email $email)
{
$this->id = $id;
$this->name = $name;
$this->email = $email;
$this->createdAt = new \DateTimeImmutable();
}
public function getId(): UserId
{
return $this->id;
}
public function getName(): string
{
return $this->name;
}
public function getEmail(): Email
{
return $this->email;
}
public function changeName(string $newName): void
{
if (strlen($newName) < 3) {
throw new \InvalidArgumentException('Name must be at least 3 characters');
}
$this->name = $newName;
}
}
<?php
// src/Domain/ValueObjects/Email.php
namespace App\Domain\ValueObjects;
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;
}
public function __toString(): string
{
return $this->value;
}
}
<?php
// src/Domain/Repositories/UserRepositoryInterface.php
namespace App\Domain\Repositories;
use App\Domain\Entities\User;
use App\Domain\ValueObjects\UserId;
interface UserRepositoryInterface
{
public function findById(UserId $id): ?User;
public function save(User $user): void;
public function delete(UserId $id): void;
}
Application层(用例层)
<?php
// src/Application/UseCases/CreateUserUseCase.php
namespace App\Application\UseCases;
use App\Domain\Entities\User;
use App\Domain\Repositories\UserRepositoryInterface;
use App\Domain\ValueObjects\Email;
use App\Domain\ValueObjects\UserId;
use App\Application\DTOs\CreateUserRequest;
use App\Application\DTOs\CreateUserResponse;
class CreateUserUseCase
{
private UserRepositoryInterface $userRepository;
public function __construct(UserRepositoryInterface $userRepository)
{
$this->userRepository = $userRepository;
}
public function execute(CreateUserRequest $request): CreateUserResponse
{
// 业务逻辑验证
$user = new User(
new UserId(),
$request->getName(),
new Email($request->getEmail())
);
// 执行其他领域的业务规则
$this->validateUniqueEmail($user->getEmail());
// 保存实体
$this->userRepository->save($user);
return new CreateUserResponse($user);
}
private function validateUniqueEmail(Email $email): void
{
$existingUser = $this->userRepository->findByEmail($email);
if ($existingUser !== null) {
throw new \RuntimeException('Email already exists');
}
}
}
<?php
// src/Application/DTOs/CreateUserRequest.php
namespace App\Application\DTOs;
class CreateUserRequest
{
private string $name;
private string $email;
public function __construct(string $name, string $email)
{
$this->name = $name;
$this->email = $email;
}
public function getName(): string
{
return $this->name;
}
public function getEmail(): string
{
return $this->email;
}
}
Infrastructure层(适配器层)
<?php
// src/Infrastructure/Persistence/DoctrineUserRepository.php
namespace App\Infrastructure\Persistence;
use App\Domain\Entities\User;
use App\Domain\Repositories\UserRepositoryInterface;
use App\Domain\ValueObjects\Email;
use App\Domain\ValueObjects\UserId;
use Doctrine\ORM\EntityManagerInterface;
class DoctrineUserRepository implements UserRepositoryInterface
{
private EntityManagerInterface $entityManager;
private string $entityClass = User::class;
public function __construct(EntityManagerInterface $entityManager)
{
$this->entityManager = $entityManager;
}
public function findById(UserId $id): ?User
{
try {
$repository = $this->entityManager->getRepository($this->entityClass);
$user = $repository->find($id);
// 转换为领域实体
return $user ? $this->toDomainEntity($user) : null;
} catch (\Exception $e) {
throw new \RuntimeException('Failed to find user: ' . $e->getMessage());
}
}
public function save(User $user): void
{
try {
// 将领域实体转换为Doctrine实体
$doctrineEntity = $this->toDoctrineEntity($user);
$this->entityManager->persist($doctrineEntity);
$this->entityManager->flush();
} catch (\Exception $e) {
throw new \RuntimeException('Failed to save user: ' . $e->getMessage());
}
}
public function delete(UserId $id): void
{
try {
$user = $this->entityManager->find($this->entityClass, $id);
if ($user) {
$this->entityManager->remove($user);
$this->entityManager->flush();
}
} catch (\Exception $e) {
throw new \RuntimeException('Failed to delete user: ' . $e->getMessage());
}
}
private function toDomainEntity($doctrineEntity): User
{
return new User(
new UserId($doctrineEntity->getId()),
$doctrineEntity->getName(),
new Email($doctrineEntity->getEmail())
);
}
private function toDoctrineEntity(User $user): object
{
$entity = new \App\Entities\User();
$entity->setName($user->getName());
$entity->setEmail($user->getEmail()->getValue());
return $entity;
}
}
Presentation层(框架/UI层)
<?php
// src/Presentation/Controllers/UserController.php
namespace App\Presentation\Controllers;
use App\Application\UseCases\CreateUserUseCase;
use App\Application\UseCases\GetUserUseCase;
use App\Application\DTOs\CreateUserRequest;
use App\Application\DTOs\GetUserRequest;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class UserController
{
private CreateUserUseCase $createUserUseCase;
private GetUserUseCase $getUserUseCase;
public function __construct(
CreateUserUseCase $createUserUseCase,
GetUserUseCase $getUserUseCase
) {
$this->createUserUseCase = $createUserUseCase;
$this->getUserUseCase = $getUserUseCase;
}
public function create(ServerRequestInterface $request): ResponseInterface
{
$body = json_decode((string)$request->getBody(), true);
try {
$userRequest = new CreateUserRequest(
$body['name'] ?? '',
$body['email'] ?? ''
);
$response = $this->createUserUseCase->execute($userRequest);
return $this->jsonResponse(201, [
'id' => (string)$response->getUser()->getId(),
'name' => $response->getUser()->getName(),
'email' => (string)$response->getUser()->getEmail()
]);
} catch (\InvalidArgumentException $e) {
return $this->jsonResponse(400, ['error' => $e->getMessage()]);
} catch (\RuntimeException $e) {
return $this->jsonResponse(500, ['error' => $e->getMessage()]);
}
}
private function jsonResponse(int $status, array $data): ResponseInterface
{
// 使用PSR-7 Response实现
$response = new \Nyholm\Psr7\Response();
$response->getBody()->write(json_encode($data));
return $response
->withStatus($status)
->withHeader('Content-Type', 'application/json');
}
}
🔧 依赖注入容器配置
<?php
// config/dependencies.php
use App\Application\UseCases\CreateUserUseCase;
use App\Application\UseCases\GetUserUseCase;
use App\Domain\Repositories\UserRepositoryInterface;
use App\Infrastructure\Persistence\DoctrineUserRepository;
use App\Presentation\Controllers\UserController;
return [
UserRepositoryInterface::class => function($container) {
return new DoctrineUserRepository($container->get('doctrine_em'));
},
CreateUserUseCase::class => function($container) {
return new CreateUserUseCase(
$container->get(UserRepositoryInterface::class)
);
},
GetUserUseCase::class => function($container) {
return new GetUserUseCase(
$container->get(UserRepositoryInterface::class)
);
},
UserController::class => function($container) {
return new UserController(
$container->get(CreateUserUseCase::class),
$container->get(GetUserUseCase::class)
);
}
];
📚 最佳实践
依赖方向规则
- 依赖只能向内:外层可以依赖内层,内层不能依赖外层
- 依赖倒置原则:面向接口编程,而不是具体实现
边界划分
✅ 正确的依赖方向
Controller → UseCase → Domain Entity
Repository Interface → Domain Entity
❌ 错误的依赖方向
Domain Entity → Controller
Controller → Repository Implementation
分层验证
// 控制器层验证(输入验证)
class UserController
{
public function create(Request $request)
{
$this->validator->validate($request, [
'email' => 'required|email',
'name' => 'required|min:3'
]);
// ... 传递到UseCase
}
}
// 用例层验证(业务规则)
class CreateUserUseCase
{
public function execute(CreateUserRequest $request)
{
// 验证业务规则
if ($this->userRepository->emailExists($request->getEmail())) {
throw new BusinessRuleException('Email already registered');
}
// ... 创建用户
}
}
// 实体层验证(数据完整性)
class User
{
public function __construct(UserId $id, string $name, Email $email)
{
if (strlen($name) < 3) {
throw new \InvalidArgumentException('Name too short');
}
// ...
}
}
使用服务提供者
// app/Providers/UserServiceProvider.php
class UserServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind(UserRepositoryInterface::class, function() {
return new RedisUserRepository($this->app->make('redis'));
});
}
}
🎯 优势和不足
优势
✅ 可测试性高:核心业务逻辑不依赖基础设施
✅ 框架无关:可以轻松切换框架
✅ 关注点分离:每个层只关注自己的职责
✅ 易于维护:业务逻辑集中在核心层
不足
❌ 代码量增加:需要更多接口和DTO
❌ 初期开发速度慢:需要更多的规划和设计
❌ 学习曲线陡峭:需要理解抽象概念
📊 实际项目中的简化方案
对于中小型项目,可以适度简化:
// 简化的分层,但保持核心原则
src/
├── Domain/ # 核心业务(实体 + 接口)
├── Application/ # 用例
├── Infrastructure/ # 存储实现
└── Presentation/ # 控制器
// 简化示例:直接使用具体类而不是接口(如果不需要多实现)
class UserService
{
private UserRepository $userRepository;
// 但保持依赖注入
public function __construct(UserRepository $userRepository)
{
$this->userRepository = $userRepository;
}
}
💡 推荐工具和框架
- Container:PHP-DI、Laravel Container
- ORM:Doctrine、Eloquent(在适当隔离后使用)
- Validation:Symfony Validator
- Testing:PHPUnit、Mockery
整洁架构的核心是理解其原则并灵活应用,而不是机械地复制结构,根据项目规模选择合适的复杂度,确保代码清晰、可维护。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播