什么是 PHP 中的依赖注入以及为什么需要它?
\n\n想象一下你在建造一所房子。与其自己制作每一块砖,你只需订购它们并使用现成的。编程中的 依赖注入(Dependency Injection,DI) 遵循同样的原则——你不在类内部创建对象,而是从外部获取它们。这使你的代码变得灵活、可测试且易于理解。
\n\n在 PHP 中,如同任何面向对象语言一样,类通常依赖于其他类。当依赖关系直接在类内部创建时,问题就出现了——这被称为紧耦合(tight coupling)。依赖注入通过从外部传递依赖关系来解决这个问题。
\n\n没有依赖注入的问题
\n考虑一个典型示例,其中 UserService 类自己创建了一个数据库对象:
<?php\nclass Database {\n public function query($sql) {\n // 查询逻辑\n return "结果: " . $sql;\n }\n}\n\nclass UserService {\n private $db;\n \n public function __construct() {\n // 紧耦合——类自己创建依赖\n $this->db = new Database();\n }\n \n public function getUser($id) {\n return $this->db->query("SELECT * FROM users WHERE id = $id");\n }\n}\n\n$service = new UserService();\necho $service->getUser(1);\n?>\n\n这种方法的缺点:
\n- \n
- 无法将
Database替换为其他实现(例如用于测试) \n - 难以测试——无法插入模拟对象(mock) \n
- 代码变得庞大且难以扩展 \n
解决方案:通过构造函数注入依赖
\n现在,我们使用依赖注入重写同一个类:
\n\n<?php\nclass UserService {\n private $db;\n \n // 依赖从外部传递\n public function __construct(Database $db) {\n $this->db = $db;\n }\n \n public function getUser($id) {\n return $this->db->query("SELECT * FROM users WHERE id = $id");\n }\n}\n\n// 单独创建依赖\n$database = new Database();\n$service = new UserService($database);\necho $service->getUser(1);\n?>\n\n现在 UserService 不知道 Database 是如何创建的。它只是使用传递给它的东西。这就是依赖注入。
PHP 中依赖注入的类型
\n有三种主要的依赖注入方式。我们逐一举例说明。
\n\n1. 构造函数注入(Constructor Injection)
\n这是最常见且推荐的方式。依赖关系在对象创建时通过构造函数传递。
\n\n<?php\nclass Logger {\n public function log($message) {\n echo "[日志]: " . $message;\n }\n}\n\nclass OrderProcessor {\n private $logger;\n \n // 构造函数中的依赖\n public function __construct(Logger $logger) {\n $this->logger = $logger;\n }\n \n public function process($order) {\n // 处理订单\n $this->logger->log("订单已处理: " . $order);\n }\n}\n\n$logger = new Logger();\n$processor = new OrderProcessor($logger);\n$processor->process("订单 #123");\n?>\n\n优点:依赖始终可用,对象始终处于有效状态。缺点:如果依赖过多,构造函数可能会变得臃肿。
\n\n2. Setter 注入(Setter Injection)
\n当依赖可能是可选的,或者需要在对象运行过程中替换时使用。
\n\n<?php\nclass MailService {\n private $transport;\n \n // 依赖的 setter 方法\n public function setTransport($transport) {\n $this->transport = $transport;\n }\n \n public function send($to, $mess