在开发软件时,经常会遇到这样的问题:一个类需要用到另一个类的功能,比如用户服务需要数据库连接。传统做法是直接在类里面创建依赖对象,但这样会让代码变得僵硬,难以替换和测试。
什么是依赖注入
依赖注入(Dependency Injection,简称 DI)就是把一个对象所依赖的其他对象,从外部传递进来,而不是在内部自己创建。这种方式让程序结构更清晰,也更容易维护和扩展。
举个生活中的例子:就像你去咖啡店点单,你不关心咖啡豆从哪来、机器怎么运作,只需要服务员把做好的咖啡递给你就行。依赖注入也是这样,你需要什么功能,框架或容器会自动“递”给你。
常见的注入方式
依赖注入主要有三种写法:构造函数注入、属性注入和方法注入。最常用的是构造函数注入,因为它能保证对象创建时依赖就已经就位。
class UserService {
private $database;
// 构造函数注入
public function __construct(Database $db) {
$this->database = $db;
}
public function getUser($id) {
return $this->database->find('user', $id);
}
}
上面这段 PHP 代码中,UserService 不再自己 new Database(),而是由外面把数据库实例传进来。这样一来,如果以后想换成缓存或其他数据源,只需要换个对象传入,不用改 UserService 的代码。
依赖注入容器的作用
当项目变大,依赖关系复杂时,手动管理这些对象传递会很麻烦。这时候就需要依赖注入容器(DI Container),它像一个管家,知道每个类需要什么,自动帮你组装好。
比如你在配置文件里说明:‘当看到 Logger 接口时,就给它一个 FileLogger 实例’。之后任何用到 Logger 的地方,容器都会自动塞进去一个 FileLogger。
// 伪代码示例:注册服务
$container->register(Logger::class, FileLogger::class);
// 使用时自动注入
$userService = $container->get(UserService::class); // 自动带上依赖
中文文档资源推荐
对于刚接触依赖注入的开发者来说,看英文资料可能有点吃力。目前一些主流框架已经提供了不错的中文文档,可以帮助理解这一概念。
例如 Laravel 框架的官方中文文档对服务容器和依赖注入有详细说明,Symfony 中文社区也有翻译完整的 DI 组件教程。另外,ThinkPHP 6 的手册中也介绍了容器和绑定机制,适合 PHP 开发者入门参考。
阅读这些中文文档时,建议先动手照着例子写一遍,再尝试修改参数观察变化。实际操作比死记概念更能体会依赖注入的好处。
小技巧:如何判断是否需要使用 DI
如果你发现自己频繁修改某个类内部的 new 关键字,或者单元测试时很难模拟某些功能,那很可能就是该考虑用依赖注入了。把变化的部分抽出来,通过参数传进去,代码立马就会变得松耦合。