类职责爆炸表现为构造函数依赖多、公有方法超12个、方法名混用多领域动词、直接调用跨层操作;应按“变化原因”而非功能相似性拆分,如UserRepository、SessionManager、UserView等,确保每个类只承担单一职责。

类职责爆炸:一眼识别“万能类”征兆
当你发现一个类同时在处理数据库连接、生成HTML、校验邮箱、发送邮件、写日志,还顺手做了缓存——它已经不是封装,是在堆砌功能。这种类通常有这些表现:__construct() 里塞了七八个依赖;public 方法超过 12 个;方法名混用不同领域动词(saveUser()、renderTable()、logError());内部直接调用 file_put_contents()、mail()、new PDO() 等跨层操作。
拆分前先划清边界:按“变化原因”而不是“功能相似”分组
别因为“都是用户相关”就把注册、登录、头像裁剪、权限检查全塞进 User 类。它们变化原因完全不同:注册流程改了不影响头像裁剪逻辑,权限模型升级也不该动登录验证代码。真正该合并的,是那些**总是一起修改**的部分。比如:
– 用户数据持久化(insert()、update()、findById())→ 拆成 UserRepository
– 用户会话管理(login()、logout()、isAuthenticated())→ 单独 SessionManager
– 用户界面渲染(toCardHtml()、toTableRow())→ 交给 UserView 或模板引擎
– 邮箱格式校验和发送 → 提取为独立 EmailValidator 和 EmailSender
private 属性不是保险柜,而是责任隔离墙
很多人以为把属性设成 private 就算封装好了,其实不然。关键看这些私有属性是否都服务于同一个明确职责。如果一个类里既有 private $pdo; 又有 private $templatePath; 还有 private $logFile;,说明它正在承担数据访问、视图渲染、日志记录三件事——private 只是把混乱锁在了内部,没解决根本问题。
实操建议:
– 每个类只持有一个核心对象引用(如 $this->userRepository),其他能力通过依赖注入传入
– 删除所有直接 new 外部类的代码(比如 new PDO()、new DateTime()),改用接口或工厂
– 如果某个 private 属性只被一两个方法使用,且和其他属性无数据流转,大概率该拆出去
构造函数参数超过 3 个时,该怀疑类的设计了
__construct() 参数多,往往意味着这个类在强行聚合多个角色。比如:function __construct(PDO $pdo, TemplateEngine $tpl, LoggerInterface $logger, Config $config, EmailService $email) —— 这不是用户类,这是调度中心。这时候应该:
– 把参数按用途分组,提取为更高层的服务类(如 UserApplicationService)
– 原类只接收它真正需要的 1–2 个协作对象(比如 UserRepository 和 UserValidator)
– 用配置或容器自动组装依赖,而非在构造函数里暴露全部细节
– 特别注意:不要为了“统一入口”而把所有依赖塞进一个基类的 __construct(),那是对继承的误用
立即学习“PHP免费学习笔记(深入)”;
越想让一个类“什么都能干”,它就越难被测试、复用和定位 Bug。真正的封装不是把东西藏起来,而是让每个类只回答一个问题:“你存在的唯一理由是什么?”问完,答案超过一句话,就该拆了。



















