php怎么实现依赖注入
依赖注入的实现方法
在PHP中实现依赖注入(Dependency Injection, DI)通常有以下几种方式:
构造函数注入
通过类的构造函数传递依赖对象。这是最常见的方式,适合强制依赖项。
class DatabaseService {
private $connection;
public function __construct(PDO $connection) {
$this->connection = $connection;
}
}
$connection = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
$databaseService = new DatabaseService($connection);
setter方法注入
通过setter方法设置依赖对象。适合可选依赖项或需要动态更换依赖的情况。
class Logger {
private $writer;
public function setWriter(WriterInterface $writer) {
$this->writer = $writer;
}
}
$logger = new Logger();
$logger->setWriter(new FileWriter());
接口注入
依赖项通过接口定义,实现类必须提供注入方法。
interface InjectLogger {
public function inject(Logger $logger);
}
class UserService implements InjectLogger {
private $logger;
public function inject(Logger $logger) {
$this->logger = $logger;
}
}
使用容器实现DI
依赖注入容器可以自动管理对象的创建和依赖关系:
简单容器实现
class Container {
private $services = [];
public function register(string $name, callable $resolver) {
$this->services[$name] = $resolver;
}
public function get(string $name) {
if (!isset($this->services[$name])) {
throw new Exception("Service not found: {$name}");
}
return $this->services[$name]($this);
}
}
$container = new Container();
$container->register('db', function() {
return new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
});
$container->register('userService', function($container) {
return new UserService($container->get('db'));
});
使用现有DI框架
主流PHP框架都提供DI容器:
Laravel容器示例
// 绑定
app()->bind('mailer', function($app) {
return new Mailer($app->make('config'));
});
// 解析
$mailer = app()->make('mailer');
Symfony容器示例
# services.yaml
services:
App\Mail\Mailer:
arguments: ['@mail.transport']
自动装配实现
现代框架支持基于类型提示的自动依赖解析:

class OrderService {
public function __construct(
private PaymentGateway $gateway,
private LoggerInterface $logger
) {}
}
// 容器会自动解析并注入PaymentGateway和LoggerInterface的实现
$orderService = $container->get(OrderService::class);
最佳实践
- 优先使用构造函数注入强制依赖
- 对可选依赖使用setter注入
- 遵循依赖倒置原则,依赖抽象而非具体实现
- 对复杂项目使用成熟的DI容器
- 避免服务定位器模式(Service Locator),它实际上是DI的反模式
通过合理使用依赖注入,可以提高代码的可测试性、可维护性和灵活性。






