Laravel中Concerns文件夹的作用是什么?与普通trait有何区别
Laravel中
Concerns目录的相关说明 目录作用与设计定位
- 这是Laravel全生态统一使用的横切逻辑拆分目录,核心是解决PHP单继承限制下,同组件内多个类需要复用逻辑、又不适合把所有逻辑都堆到基类的问题——毕竟基类塞太多无关逻辑,继承它的所有类都会被强制带上没用的代码,臃肿得很。
- 各个组件下的Concerns目录是严格服务于当前组件的,不会跨组件调用:比如Database下的Concerns只给查询构造器、连接类、模型这些数据库相关类用,绝对不会被Http层的请求、响应类引用。
- 本质就是Laravel团队在PHP原生trait能力之上定的一套目录约定,没有特殊语法改造,最大的好处是可维护性强:找某个组件的复用逻辑,直接进对应组件的Concerns目录翻就行,不用全局到处搜trait。
Concerns内trait的分类
这里面存的全是和宿主类强绑定的内聚型trait,没有那种跨项目通用的工具类trait,基本可以分成三类:
- 能力封装类:给宿主类直接提供一整组完整功能,比如Http组件里的
InteractsWithInput,把所有获取请求参数、过滤参数、判断参数存在的逻辑全封装好了,请求类只要use这个trait,直接就能用全套输入处理能力,不用自己写一行重复代码。 - 流程复用类:比如数据库组件里的
BuildsQueries,把查询构造的通用流程、分页逻辑、结果集处理逻辑全封装了,不管是MySQL、PostgreSQL还是SQL Server的查询驱动类,只要use这个trait,只需要实现各个驱动差异化的底层方法就行,通用流程完全不用重复写。 - 交互能力类:比如Console组件里的
InteractsWithIO,封装了命令行参数解析、输入读取、输出格式化、进度条这些所有和控制台交互的逻辑,所有自定义命令类use之后,直接就能用$this->info()、$this->ask()这类方法。
这些trait都没法独立实例化使用,所有逻辑都是围绕use它的宿主类设计的,很多时候甚至会直接调用宿主类里定义的属性、预留的方法,不会为了通用做无意义的兼容。
和普通PHP Trait的核心差异
本质上它就是标准PHP trait,没有做任何语法层面的改造,差异全在设计和使用约定上:
- 绑定强度不同:普通PHP trait很多是通用工具性质的,比如一个格式化时间的trait可能全项目随便用,对宿主类没有任何要求;但Concerns里的trait和宿主类是强绑定的,通常会明确要求宿主类必须实现指定方法、存在指定属性,否则运行直接报错。
- 职责粒度不同:普通trait经常会塞各种零散的工具方法,一个trait里什么杂七杂八的逻辑都有;但Concerns里的每个trait职责高度单一,一个trait只解决一类场景问题,比如
ManagesTransactions就只管数据库事务的开启、提交、回滚、嵌套事务逻辑,半毛钱和事务无关的代码都不会放进去。 - 可见性规则不同:普通trait里的方法大多是public的通用方法,随便在哪都能调;Concerns里的trait会大量使用protected方法,只给宿主类内部调用,不会对外暴露成公共API,本质就是给宿主类的内部逻辑做拆分,相当于“内部代码块拆分”,不是给外部用的。
- 归属逻辑不同:普通trait很多会被扔在全局的
app/Traits这类目录里,和所属的业务逻辑、组件逻辑脱节;Concerns目录是跟着所属组件走的,组件如果被移除,对应的Concerns目录也会一起删掉,不会留下没人用的冗余代码。
内容的提问来源于stack exchange,提问作者Nothehi
相关产品推荐
相关产品推荐

