Laravel核心层与基础设施层:架构边界与协同之道
目录导读
- 引文:分层不是割裂,而是协作的契约
- 核心层:业务逻辑的“心脏”
- 核心层包含哪些组件?
- 核心层如何保持纯净?
- 基础设施层:外界的“翻译官”
- 基础设施层的典型角色
- 依赖倒置原则的体现
- 两者如何分?三问法快速判断
- 常见误区与最佳实践
- 问答环节:开发者最常问的3个问题
引文:分层不是割裂,而是协作的契约
很多Laravel开发者做完第一个项目后,会陷入一个困惑:控制器里写数据库查询到底好不好?服务类应该放哪里? 这背后其实藏着一个架构核心问题——核心层(Core Layer)与基础设施层(Infrastructure Layer)的边界在哪里?

Laravel本身并没有强制目录结构,但成熟的架构分层能让你在项目膨胀时不至于“改一处崩一片”,根据Google与Bing对技术文章的索引偏好,清晰的、有实践指导的架构分析往往排名更靠前,本文将结合Martin Fowler的分层架构思想与Laravel生态特性,帮你彻底搞懂这两个层的“分”与“合”。
核心层:业务逻辑的“心脏”
核心层是与框架无关、与外部服务无关的纯业务逻辑集合,它只关心“做什么”,而不关心“怎么做”。
核心层包含哪些组件?
- 实体(Entities):如
User、Order,它们包含业务的约束与行为(订单总额必须大于0”)。 - 值对象(Value Objects):如
Email、Money,封装对属性的校验与运算。 - 领域服务(Domain Services):当某个行为不属于单一实体时,如
PaymentScheduler(处理订阅扣费时间计算)。 - 仓库接口(Repository Interfaces):注意,这里只是接口定义,不是具体实现。
核心层如何保持纯净?
- 零外部依赖:不引用Eloquent、不引用HTTP请求、不引用缓存驱动。
- 只依赖PHP原生类与你自己定义的接口。
一个错误例子:
class Order
{
public function process()
{
// 直接调用Eloquent——核心层污染!
DB::table('logs')->insert(...);
}
}
正确做法: 核心层只定义LoggerInterface,由基础设施层去实现它。
基础设施层:外界的“翻译官”
基础设施层负责所有与外部世界的交互:数据库、文件系统、API调用、邮件发送、缓存等,它的任务是将核心层的抽象接口翻译成具体实现。
基础设施层的典型角色
- Eloquent模型与Repository实现:让核心层通过接口访问数据,而不知晓底层是MySQL还是Redis。
- 第三方服务封装:比如把
Guzzle请求封装成SmsSenderInterface的实现。 - HTTP控制器与路由:控制器只负责“拿到输入,调用核心层,返回响应”,不写业务逻辑。
依赖倒置原则的体现
核心层定义接口,基础设施层依赖这些接口并实现它们,这就是依赖倒置(DIP)——高层模块(核心层)不依赖低层模块(基础设施层),两者都依赖抽象。
目录结构示意(以领域驱动设计风格为例):
app/
├── Core/
│ ├── Domain/
│ │ ├── User/
│ │ │ ├── User.php (实体)
│ │ │ ├── UserRepositoryInterface.php (接口)
│ │ │ └── UserService.php (领域服务)
│ │ └── ValueObjects/
│ └── Application/ (用例/应用服务)
├── Infrastructure/
│ ├── Persistence/
│ │ └── EloquentUserRepository.php (实现)
│ ├── Payment/
│ └── Mail/
└── Http/
├── Controllers/
└── Middleware/
两者如何分?三问法快速判断
当你犹豫某段代码该放哪一层时,问自己三个问题:
-
这段代码是否依赖Laravel的某个门面(Facade)或具体类?
是 → 大概率属于基础设施层。
否 → 继续问。 -
如果我把数据库从MySQL换成PostgreSQL,这段代码需要改吗?
需要改 → 基础设施层。
不需要改 → 核心层。 -
这段代码是否直接操作HTTP请求或响应?
是 → 基础设施层(或HTTP层)。
否 → 核心层。
经典边界:
- “计算订单折扣” → 核心层(可单元测试,无外部依赖)。
- “发送折扣邮件” → 基础设施层(依赖邮件驱动)。
- “从请求中获取用户ID” → HTTP层(控制器或中间件)。
常见误区与最佳实践
误区1:把所有Service都塞进Infrastructure
业务复杂的Service应属于核心层,比如InvoiceService里计算税额的逻辑,就不应写在基础设施中。
误区2:核心层直接使用Laravel的Collection
Collection虽好用,但它是一个具体类,若核心层引用了它,就与Laravel耦合了,建议核心层使用原生数组或自定义集合类。
最佳实践:用Laravel的ServiceProvider绑定接口与实现
在AppServiceProvider中:
$this->app->bind(UserRepositoryInterface::class, EloquentUserRepository::class);
这样核心层只知道接口,不知道具体实现。
问答环节:开发者最常问的3个问题
Q1:核心层可以用Laravel的Eloquent模型吗?
A: 强烈不建议,Eloquent模型直接继承了Model类,这意味着你的核心层依赖了Laravel ORM,一旦将来你想改用Doctrine或原生SQL,就得重写核心层,核心层应当面向接口编程,数据访问的实现细节交给基础设施层。
Q2:控制器到底算哪一层?
A: 控制器通常属于HTTP层(或适配器层),它是基础设施层的一部分,它的职责是:解析请求、调用应用服务(核心层)、构造响应,如果你发现控制器里写了复杂的业务计算,那就把它移到核心层。
Q3:如果项目很小,有必要分这么细吗?
A: 看规模,如果你做的是只有一个表单的简单页面,确实不必强行分层,但只要有二次开发、团队协作或计划长期维护,分层就是“前期成本,后期收益”,你可以从简单的Repository模式开始,后续逐步细化。
分层不是目的,可维护才是
核心层与基础设施层的划分,本质是让变化与稳定各归其位,核心层足够稳定,成为业务的“宪法”;基础设施层灵活多变,成为适应技术演进的“口岸”,在Laravel中践行这一原则,你的代码将更容易测试、更清晰、更经得起时间考验。
框架是用来实现你的业务,而不是让你的业务去适应框架。