php怎么实现依赖注入
依赖注入的实现方式
在PHP中实现依赖注入(Dependency Injection,DI)可以通过多种方式完成,以下是常见的几种方法:
构造函数注入
通过类的构造函数传递依赖对象。这是最常用的依赖注入方式。
class DatabaseConnection {
private $config;
public function __construct(array $config) {
$this->config = $config;
}
}
$config = ['host' => 'localhost', 'user' => 'root'];
$db = new DatabaseConnection($config);
属性注入
通过类的属性直接设置依赖对象。这种方式灵活性较高,但可能破坏封装性。
class Logger {
public $writer;
}
$logger = new Logger();
$logger->writer = new FileWriter();
方法注入
通过方法参数传递依赖对象,适合临时性的依赖关系。
class UserService {
public function save(User $user, Logger $logger) {
$logger->log('User saved');
// 保存用户逻辑
}
}
$service = new UserService();
$service->save($user, new Logger());
依赖注入容器
对于复杂的依赖关系,可以使用依赖注入容器(DI Container)来管理对象的创建和依赖关系。
简单的DI容器实现
class Container {
protected $instances = [];
public function bind($abstract, $concrete = null) {
if (is_null($concrete)) {
$concrete = $abstract;
}
$this->instances[$abstract] = $concrete;
}
public function make($abstract, $parameters = []) {
if (!isset($this->instances[$abstract])) {
$this->bind($abstract);
}
return $this->resolve($this->instances[$abstract], $parameters);
}
protected function resolve($concrete, $parameters) {
$reflector = new ReflectionClass($concrete);
$constructor = $reflector->getConstructor();
if (is_null($constructor)) {
return new $concrete();
}
$dependencies = $constructor->getParameters();
$instances = $this->resolveDependencies($dependencies, $parameters);
return $reflector->newInstanceArgs($instances);
}
protected function resolveDependencies($dependencies, $parameters) {
$results = [];
foreach ($dependencies as $dependency) {
if (isset($parameters[$dependency->name])) {
$results[] = $parameters[$dependency->name];
} else {
$results[] = $this->make($dependency->getClass()->name);
}
}
return $results;
}
}
使用DI容器
$container = new Container();
$container->bind('DatabaseConnection', 'MyDatabaseConnection');
$db = $container->make('DatabaseConnection');
使用现有的DI框架
PHP生态系统中有许多成熟的DI容器框架可供选择:
- Laravel的服务容器:Laravel框架内置了强大的DI容器
- PHP-DI:专门为PHP设计的依赖注入容器
- Symfony DependencyInjection组件:Symfony框架的DI组件
使用PHP-DI示例
use DI\ContainerBuilder;
$builder = new ContainerBuilder();
$builder->addDefinitions([
'Database' => function() {
return new DatabaseConnection();
},
'Logger' => function() {
return new FileLogger();
}
]);
$container = $builder->build();
$db = $container->get('Database');
$logger = $container->get('Logger');
自动装配
现代DI容器通常支持自动装配(Autowiring),可以自动解析类依赖关系而无需手动配置。
class UserController {
private $userService;
public function __construct(UserService $userService) {
$this->userService = $userService;
}
}
// 使用支持自动装配的容器
$container = new Container();
$controller = $container->make('UserController');
// 会自动解析UserService及其所有依赖
接口绑定
在实际应用中,通常会针对接口进行绑定,而不是具体实现类。
interface LoggerInterface {
public function log($message);
}
class FileLogger implements LoggerInterface {
public function log($message) {
// 实现日志记录
}
}
$container->bind(LoggerInterface::class, FileLogger::class);
$logger = $container->make(LoggerInterface::class);
通过以上方法,可以在PHP项目中实现灵活、可测试的依赖注入架构。选择哪种方式取决于项目规模、复杂度和团队偏好。







