本文目录导读:

- 核心比喻:国家机密文件
- PHP 洋葱架构的典型分层(从内到外)
- 核心机制:依赖反转(Dependency Inversion Principle)
- 为什么不用传统三层架构(Controller -> Service -> Model)?
- 图例化理解
- 对 PHP 开发者的实际价值
- 总结一句话:
这是一个非常深刻的好问题。PHP 洋葱架构(Onion Architecture) 的核心思想是:让业务逻辑独立于技术实现,理解它的关键在于:由内向外依赖,外部向内调用。
下面我通过一个通俗易懂的比喻和具体的 PHP 代码例子来解释。
核心比喻:国家机密文件
想象一下,有一个国家最重要的 核心机密文件。
- 内层(核心层):文件本身(业务逻辑),它是最重要的,不能直接接触外界,也不关心你是用中文还是英文写(不关心数据库、框架等)。
- 中层(应用服务层):负责解读文件内容的文职人员,他知道文件该给谁看,但自己不动手去送(协调工作流)。
- 外层(基础设施层):送文件的快递员、存放文件的保险箱、张贴文件的公告板,他们具体干活,但不懂文件内容(具体技术实现)。
关键规则:
- 依赖方向(由内向外):核心层(文件)完全不知道外层(快递员)的存在,但外层(快递员)依赖核心层(文件内容)来工作。
- 控制反转(DIP):核心层定义接口(如何存储文件”),外层去实现这个接口,核心层不直接调用“快递员”,而是通过一个接口,让“快递员”去实现。
PHP 洋葱架构的典型分层(从内到外)
-
领域层(Domain Model / 核心)
- 实体、值对象、聚合、领域服务、仓储接口、领域事件。
- 职责:完全不依赖任何框架、数据库、Web 服务器,这是你的 “业务大脑”。
- PHP 例子:一个
Order类,里面有calculateTotal()方法,它不知道自己的数据是存在 MySQL 还是 Redis 里。
-
应用层(Application Service / 中层)
- 应用服务、DTO(数据传输对象)、用例。
- 职责:负责协调业务流程,它调用领域层的接口,但不执行具体的技术操作,它不包含业务规则,只编排业务规则。
- PHP 例子:
CreateOrderService类,它的execute()方法会调用OrderRepository(接口)的save()方法,但自己不去写INSERT SQL。
-
基础设施层(Infrastructure / 外层)
- 数据持久化(Eloquent、Doctrine)、外部 API 调用、缓存、邮件发送、文件系统操作。
- 职责:实现应用层和领域层定义的接口,与框架、数据库、第三方服务紧密耦合。
- PHP 例子:
MysqlOrderRepository实现了OrderRepository接口,里面使用 Laravel 的DB::table()或 Eloquent ORM。
-
表示层(Presentation / 最外层)
- HTTP 控制器、命令行脚本、API 路由、视图模板。
- 职责:接收用户输入,调用应用层服务,返回响应,它是最脏的层次(耦合 Web 技术)。
核心机制:依赖反转(Dependency Inversion Principle)
这是洋葱架构的灵魂,内层定义接口,外层实现接口,外层依赖内层的抽象。
错误的方式(传统三层架构常见):
// 领域层(核心)直接依赖了具体的外部实现(MySQL),这是错误的!
class OrderService {
public function createOrder($data) {
// 直接 new 了一个数据库模型,导致核心层依赖了 Eloquent ORM
$order = new EloquentOrder();
$order->save();
}
}
正确的洋葱方式: 领域层定义接口(内层抽象):
// src/Domain/Repository/OrderRepositoryInterface.php
namespace App\Domain\Repository;
interface OrderRepositoryInterface
{
public function save(Order $order): void;
}
应用层使用该接口(中层编排):
// src/Application/Service/CreateOrderService.php
namespace App\Application\Service;
use App\Domain\Repository\OrderRepositoryInterface;
class CreateOrderService
{
// 依赖抽象(接口),而不是具体实现
private OrderRepositoryInterface $orderRepo;
public function __construct(OrderRepositoryInterface $orderRepo)
{
$this->orderRepo = $orderRepo;
}
public function execute( array $orderData ): void
{
// 1. 执行业务逻辑
$order = new \App\Domain\Model\Order( $orderData );
// 2. 使用接口保存(不关心是 MySQL 还是 MongoDB)
$this->orderRepo->save( $order );
}
}
基础设施层实现接口(外层具体实现):
// src/Infrastructure/Persistence/MysqlOrderRepository.php
namespace App\Infrastructure\Persistence;
use App\Domain\Repository\OrderRepositoryInterface;
use App\Domain\Model\Order;
// 外层实现了内层定义的接口
class MysqlOrderRepository implements OrderRepositoryInterface
{
public function save(Order $order): void
{
// 这里才真正使用 Laravel 的 Eloquent 或 DB Facade
\App\Models\Order::create([
'id' => $order->getId(),
'total' => $order->getTotal(),
// ...
]);
}
}
使用依赖注入容器绑定(应用启动时):
// 通常在 AppServiceProvider 或 routes/web.php 中 $this->app->bind(OrderRepositoryInterface::class, MysqlOrderRepository::class);
为什么不用传统三层架构(Controller -> Service -> Model)?
传统三层架构(常见于初学者或快速开发)会面临一个问题:业务逻辑被技术实现绑架。
- 你的
UserService里直接new UserModel(), 用的是 Eloquent。 - 如果将来公司决定从 MySQL 迁移到 MongoDB,或者从 Laravel 换到 Symfony,你需要修改业务逻辑层的代码。
- 单元测试困难:测试业务逻辑需要连接数据库。
图例化理解
[ 外部依赖 ] [ 框架 ] [ 数据库 ]
↓ ↓ ↓
┌─────────────────────────────────────────┐
│ (4) 表示层/Presentation │ ← 最外层,依赖方向向内
│ Controllers, Views, API Routes │
└────────────────┬────────────────────────┘
│ 调用应用层
┌────────────────▼────────────────────────┐
│ (3) 基础设施层/Infrastructure │ ← 外层,实现接口
│ DB Logging, Email, Cache, API │
└────────────────┬────────────────────────┘
│ 实现领域层接口
┌────────────────▼────────────────────────┐
│ (2) 应用层/Application │ ← 中层,编排业务流程
│ Application Services, DTOs │
└────────────────┬────────────────────────┘
│ 调用领域接口(无具体实现)
┌────────────────▼────────────────────────┐
│ (1) 领域层/Domain │ ← 最内层,核心业务逻辑
│ Entities, Value Objects, Interfaces │
└─────────────────────────────────────────┘
↑ ↑ ↑
[ 业务规则 ] [ 领域事件 ] [ 仓储接口 ]
对 PHP 开发者的实际价值
- 易测试:领域层和应用层可以脱离 Laravel 等框架进行纯单元测试。
- 易替换:换数据库、换缓存、甚至换框架(从 Laravel 换到 Symfony),只需要替换外层的“Adapter”,业务逻辑纹丝不动。
- 代码组织:大项目下,业务逻辑不会散落在各种 Service、Model、Helper 里,核心是
Domain下的实体和接口。 - 团队协作:后端业务专家可以专心写
Domain,框架专家专心实现Infrastructure。
总结一句话:
洋葱架构 = 把“业务核心”封装在最里面,用依赖反转(接口)隔离外部技术,由外向内依赖,从内向外调用。
这样,即使 PHP 版本升级、框架变更、数据库迁移,你的业务核心代码依然稳定如山。
版权声明: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直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播