PHP项目中依赖注入不是可选优化,而是类协作时避免手动new失控的必然选择;它通过构造函数类型提示实现编译时解耦,使接口替换、单元测试、多环境切换成为可能,而工厂模式无法解决生命周期管理与配置集中化问题。
PHP项目不是“需要”依赖注入,而是只要业务逻辑开始跨类协作,手动就会立刻失控。
你写一个
调用
发邮件,再调用
记日志,再调用
缓存结果——这四个类如果全靠构造函数里
出来,那换数据库驱动、切日志后端、改缓存引擎时,你得翻遍所有服务类去改实例化代码。
当你在类里写
,就等于锁死了实现
常见错误现象:
构造函数直接
;测试时想 mock 数据库?不可能——
是硬编码,不是接口契约。
接口无法替换:哪怕你写了
,只要类内部
了具体实现,接口就形同虚设
单元测试失效:无法注入测试替身(mock/stub),只能走真实 DB/网络,CI 流水线慢到崩溃
环境切换困难:开发用 SQLite、测试用 MySQL、生产用 PostgreSQL?靠改代码不是运维,是人肉部署脚本
参数注入才是解耦起点
这不是“更优雅的写法”,而是把依赖关系从运行时(
)移到编译时(类型提示),让容器能看懂你要什么。
必须用类型提示:参数写
,而不是
或
,否则自动装配失效
不要在构造函数里做实际工作:只赋值,不连接、不查询、不初始化外部资源——那些该交给工厂或生命周期回调
避免可选依赖:像
会破坏自动装配链,真要可选,用 setter 或容器条件绑定
为什么不能只靠工厂类?
工厂看似解耦,实则把
从类里挪到工厂里,问题照旧:工厂本身变成高耦合中心,且无法支持多实例策略(比如单例 vs 每次新建)。
PHP 8.5.5
PHP 8.5.5 是 PHP 8.5 分支的维护更新版本。该版本延续了“小步快跑”的迭代逻辑,通过深度错误修复、底层性能微调以及安全加固,旨在为开发者提供一个更健壮、更高效的运行环境。该版本严格遵守语义化版本规范,不包含破坏性变更。
下载
立即学习
“
PHP免费学习笔记(深入)
”;
工厂难测试:你得 mock 工厂返回值,而工厂又可能依赖其他工厂,形成工厂套娃
生命周期失控:工厂无法统一管理单例、作用域(request/scoped)、销毁逻辑(如 PDO 连接关闭)
配置分散:每个工厂一个文件,改一个 DB 配置要翻 5 个工厂,而容器配置集中在一个地方
自动装配不是银弹,接口必须显式绑定
PHP-DI、Laravel 容器默认启用自动装配,但对
这类抽象,它不知道你想要 Monolog 还是 Syslog。不绑定,运行时报
。
必须提前注册:在容器启动时执行
别信“零配置”宣传:自动装配只解决“已知具体类”的依赖链,接口/抽象类永远需要人工指路
警惕循环依赖:A 依赖 B,B 又依赖 A —— 容器报错信息往往模糊,建议用
的
模式定位
最常被忽略的一点:解耦不是目的,是手段。真正关键的是——你能否在不改任何业务类的前提下,把
换成
,把
切到
,甚至把整个支付模块替换成第三方 SDK。做不到这点,DI 就只是换了个姿势写
。
newUserServiceMailerLoggerCachenewnewUserRepositorynew MySQLConnection(...)newDatabaseInterfacenew__construct()newDatabaseInterface $db$dbobject $dbLoggerInterface $logger = nullnewLoggerInterfaceNo entry or class found$container->set(LoggerInterface::class, MonologLogger::class)php-di/php-didebugFileLoggerSentryLoggerMySQLDriverPostgreSQLDrivernew