本文目录导读:

我来通过一个实际例子,详细介绍PHP依赖注入容器(DIC)的用法。
什么是依赖注入容器
依赖注入容器是管理类依赖的工具,它负责:
- 创建对象及其依赖
- 存储已注册的服务
- 自动解析依赖关系
基本使用示例
使用Pimple容器(最流行的轻量级容器)
<?php
// 1. 安装
// composer require pimple/pimple
// 2. 基本容器使用
require 'vendor/autoload.php';
use Pimple\Container;
$container = new Container();
// 注册服务(延迟加载)
$container['db'] = function ($c) {
return new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
};
// 使用服务
$db = $container['db'];
完整业务示例
<?php
use Pimple\Container;
class UserRepository
{
private $db;
public function __construct(PDO $db)
{
$this->db = $db;
}
public function findUser($id)
{
$stmt = $this->db->prepare('SELECT * FROM users WHERE id = ?');
$stmt->execute([$id]);
return $stmt->fetch();
}
}
class UserService
{
private $userRepository;
private $logger;
public function __construct(UserRepository $userRepository, Logger $logger)
{
$this->userRepository = $userRepository;
$this->logger = $logger;
}
public function getUserProfile($userId)
{
$this->logger->log("Fetching user: $userId");
return $this->userRepository->findUser($userId);
}
}
class Logger
{
public function log($message)
{
echo "[LOG] $message\n";
}
}
// 配置容器
$container = new Container();
// 注册基础服务
$container['db'] = function ($c) {
return new PDO('mysql:host=localhost;dbname=test', 'root', 'password');
};
$container['logger'] = function ($c) {
return new Logger();
};
// 注册业务服务
$container['user_repository'] = function ($c) {
return new UserRepository($c['db']);
};
$container['user_service'] = function ($c) {
return new UserService(
$c['user_repository'],
$c['logger']
);
};
// 使用容器获取服务
$userService = $container['user_service'];
$user = $userService->getUserProfile(123);
print_r($user);
使用PHP-DI(功能更完整的容器)
<?php
// 安装
// composer require php-di/php-di
use DI\Container;
use DI\ContainerBuilder;
// 创建容器
$containerBuilder = new ContainerBuilder();
$containerBuilder->useAutowiring(true); // 启用自动装配
$container = $containerBuilder->build();
// 简单使用 - 自动解析依赖
class Mailer
{
public function send($to, $message)
{
echo "Sending mail to $to: $message\n";
}
}
class UserNotifier
{
private $mailer;
public function __construct(Mailer $mailer)
{
$this->mailer = $mailer;
}
public function notifyUser($userId)
{
$this->mailer->send("user$userId@example.com", "Welcome!");
}
}
// 容器自动解析所有依赖
$notifier = $container->get(UserNotifier::class);
$notifier->notifyUser(1);
// 手动配置
$containerBuilder->addDefinitions([
Mailer::class => function () {
return new Mailer();
},
// 也可以绑定接口
'Logger' => function () {
return new Logger();
},
]);
// 使用参数注入
class EmailService
{
private $smtpHost;
private $smtpPort;
public function __construct($smtpHost = 'localhost', $smtpPort = 25)
{
$this->smtpHost = $smtpHost;
$this->smtpPort = $smtpPort;
}
}
$containerBuilder->addDefinitions([
EmailService::class => function () {
return new EmailService('smtp.example.com', 587);
},
]);
使用Laravel的服务容器
<?php
// Laravel框架中的使用
// 1. 绑定服务
app()->bind('PaymentGateway', function ($app) {
return new PaymentGateway('api-key');
});
// 2. 单例绑定
app()->singleton('Logger', function ($app) {
return new Logger();
});
// 3. 自动注入到控制器
class OrderController extends Controller
{
private $paymentGateway;
// Laravel自动解析依赖
public function __construct(PaymentGateway $paymentGateway)
{
$this->paymentGateway = $paymentGateway;
}
public function processOrder()
{
return $this->paymentGateway->charge();
}
}
// 4. 使用门面/Facade
public function test()
{
$payment = app('PaymentGateway');
$logger = app('Logger');
}
自定义简单容器
<?php
class SimpleContainer
{
private $bindings = [];
private $instances = [];
// 绑定服务
public function bind($abstract, $concrete = null)
{
$this->bindings[$abstract] = $concrete ?? $abstract;
}
// 绑定单例
public function singleton($abstract, $concrete = null)
{
$this->bind($abstract, $concrete);
$this->bindings[$abstract] = function ($container) use ($abstract) {
if (!isset($this->instances[$abstract])) {
$this->instances[$abstract] = $container->build($abstract);
}
return $this->instances[$abstract];
};
}
// 解析服务
public function make($abstract)
{
if (isset($this->bindings[$abstract])) {
$binding = $this->bindings[$abstract];
if ($binding instanceof \Closure) {
return $binding($this);
}
return $this->build($binding);
}
return $this->build($abstract);
}
// 自动构建类(实现简单的自动注入)
private function build($class)
{
$reflector = new ReflectionClass($class);
if (!$reflector->isInstantiable()) {
throw new Exception("Class $class is not instantiable");
}
$constructor = $reflector->getConstructor();
if (is_null($constructor)) {
return new $class;
}
$parameters = $constructor->getParameters();
$dependencies = [];
foreach ($parameters as $parameter) {
$dependency = $parameter->getType();
if ($dependency && !$dependency->isBuiltin()) {
// 递归解析依赖
$dependencies[] = $this->make($dependency->getName());
} else {
// 基本类型参数,检查是否有默认值
if ($parameter->isDefaultValueAvailable()) {
$dependencies[] = $parameter->getDefaultValue();
} else {
throw new Exception("Cannot resolve dependency");
}
}
}
return $reflector->newInstanceArgs($dependencies);
}
}
// 使用自定义容器
$container = new SimpleContainer();
// 注册服务
$container->bind('Logger', function () {
return new Logger();
});
// 自动解析UserService及其所有依赖
$userService = $container->make(UserService::class);
最佳实践
<?php
// 1. 使用接口抽象
interface PaymentGatewayInterface
{
public function charge(float $amount);
}
class StripeGateway implements PaymentGatewayInterface
{
public function charge(float $amount)
{
// 实现
}
}
class PaypalGateway implements PaymentGatewayInterface
{
public function charge(float $amount)
{
// 实现
}
}
// 2. 配置驱动
$config = [
'payment_gateway' => 'stripe',
];
$container['payment_gateway'] = function ($c) use ($config) {
switch ($config['payment_gateway']) {
case 'stripe':
return new StripeGateway();
case 'paypal':
return new PaypalGateway();
default:
throw new \Exception('Unknown gateway');
}
};
// 3. 延迟加载
$container['heavy_service'] = function ($c) {
// 仅有需要时才创建
return new HeavyService();
};
注意事项
- 性能考虑:使用
singleton减少重复创建 - 调试方便:容器应该支持查看已注册的服务
- 避免服务定位器反模式:不要过度依赖容器
- 依赖关系清晰:尽量明确显式的依赖
依赖注入容器的核心优势:
- 解耦:类之间不直接实例化依赖
- 可测试性:方便替换mock对象
- 可维护性:统一管理服务
- 灵活性:方便切换实现
选择合适的容器(Pimple、PHP-DI或框架内置的)取决于项目复杂度和你需要的高级特性。