php实现di
依赖注入(DI)实现方法
在PHP中实现依赖注入(Dependency Injection,DI)可以通过手动注入或使用容器两种方式完成。以下是具体实现方法:
手动依赖注入
通过构造函数或方法直接传递依赖对象,不依赖外部容器。
class DatabaseConnection {
public function connect() {
return "Database connected";
}
}
class UserRepository {
private $db;
public function __construct(DatabaseConnection $db) {
$this->db = $db;
}
public function getUsers() {
return $this->db->connect() . " -> Fetching users";
}
}
// 手动注入
$db = new DatabaseConnection();
$userRepo = new UserRepository($db);
echo $userRepo->getUsers();
使用DI容器
通过容器管理依赖关系,自动解析和注入依赖项。以下是简易容器实现:
class Container {
private $bindings = [];
public function bind($abstract, $concrete) {
$this->bindings[$abstract] = $concrete;
}
public function resolve($abstract) {
if (isset($this->bindings[$abstract])) {
$concrete = $this->bindings[$abstract];
if (is_callable($concrete)) {
return $concrete($this);
}
return $this->resolve($concrete);
}
$reflector = new ReflectionClass($abstract);
$constructor = $reflector->getConstructor();
if (is_null($constructor)) {
return new $abstract;
}
$parameters = $constructor->getParameters();
$dependencies = array_map(
function($param) {
return $this->resolve($param->getClass()->name);
},
$parameters
);
return $reflector->newInstanceArgs($dependencies);
}
}
// 使用容器
$container = new Container();
$container->bind(DatabaseConnection::class, DatabaseConnection::class);
$userRepo = $container->resolve(UserRepository::class);
echo $userRepo->getUsers();
使用现有DI库
推荐使用成熟的DI库如PHP-DI或Symfony DependencyInjection组件:
// 使用PHP-DI示例
require_once 'vendor/autoload.php';
use DI\ContainerBuilder;
$builder = new ContainerBuilder();
$builder->addDefinitions([
DatabaseConnection::class => DI\create(DatabaseConnection::class)
]);
$container = $builder->build();
$userRepo = $container->get(UserRepository::class);
echo $userRepo->getUsers();
接口绑定实践
通过接口绑定实现更松散的耦合:
interface DatabaseInterface {
public function connect();
}
class MySQLConnection implements DatabaseInterface {
public function connect() {
return "MySQL connected";
}
}
// 容器配置
$container->bind(DatabaseInterface::class, MySQLConnection::class);
最佳实践建议
- 优先使用接口而非具体类进行类型提示
- 将容器配置与业务代码分离
- 对于小型项目手动注入足够,大型项目建议使用成熟DI库
- 避免服务定位器模式(直接从容器中解析依赖),应通过构造函数注入







