Symfony 依赖注入容器详解
Symfony 的依赖注入容器是其最核心的组件之一,它实现了"控制反转"(IoC)设计模式。

基本概念
依赖注入:将对象的依赖关系从内部创建转移到外部注入
// 不好的做法 - 硬编码依赖
class UserController {
private $repository;
public function __construct() {
$this->repository = new UserRepository(); // 紧耦合
}
}
// 好的做法 - 依赖注入
class UserController {
private $repository;
public function __construct(UserRepository $repository) {
$this->repository = $repository; // 松耦合
}
}
服务容器核心服务
// 1. 注册服务(services.yaml)
services:
# 默认自动注册
App\Service\:
resource: '../src/Service/*'
autowire: true
autoconfigure: true
# 手动注册服务
App\Service\MailService:
arguments:
$mailer: '@Symfony\Component\Mailer\MailerInterface'
$adminEmail: 'admin@example.com'
# 注册接口实现
App\Repository\UserRepositoryInterface:
alias: App\Repository\DoctrineUserRepository
public: true
服务容器核心组件
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
class CustomContainerConfiguration
{
public function configure()
{
$container = new ContainerBuilder();
// 1. 定义服务
$container->register('app.mailer', MailerService::class)
->setArguments([
new Reference('Symfony\Component\Mailer\MailerInterface'),
'%admin_email%'
])
->setPublic(true);
// 2. 设置参数
$container->setParameter('admin_email', 'admin@example.com');
// 3. 设置标签
$container->register('app.event_listener', EventListener::class)
->addTag('kernel.event_listener', ['event' => 'kernel.response']);
return $container;
}
}
高级特性
1 自动装配 (Autowiring)
// config/services.yaml
services:
_defaults:
autowire: true # 自动注入
autoconfigure: true # 自动配置
public: false # 默认私有
App\:
resource: '../src/*'
exclude: '../src/{DependencyInjection,Entity,Migrations,Tests}'
// 控制器中使用
class ProductController extends AbstractController
{
private $productService;
private $entityManager;
// Symfony 会自动注入这些依赖
public function __construct(
ProductService $productService,
EntityManagerInterface $entityManager
) {
$this->productService = $productService;
$this->entityManager = $entityManager;
}
}
2 服务标签 (Service Tags)
// 自定义标签
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
class CustomCompilerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$taggedServices = $container->findTaggedServiceIds('app.processor');
foreach ($taggedServices as $id => $tags) {
// 处理标签服务
$definition = $container->getDefinition($id);
$definition->addMethodCall('setLogger', [
new Reference('logger')
]);
}
}
}
// 服务定义添加标签
services:
App\Service\PdfProcessor:
tags:
- { name: 'app.processor', priority: 10, format: 'pdf' }
3 服务装饰器 (Service Decoration)
// 装饰原有服务
services:
App\Service\OriginalMailer:
class: App\Service\MailerService
App\Decorator\LoggingMailer:
decorates: App\Service\OriginalMailer
decoration_inner_name: 'app.original_mailer'
arguments:
- '@App\Decorator\LoggingMailer.inner'
# 或者使用接口装饰
App\Decorator\CachingMailer:
decorates: App\Service\MailerService
decoration_on_invalid: exception
arguments:
- '@.inner'
4 容器编译优化
// 自定义编译器
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
class PerformanceCompilerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
// 1. 优化自动加载
foreach ($container->getDefinitions() as $id => $definition) {
if ($definition->isPublic()) {
$definition->setPublic(false);
$container->setAlias($id, $definition->getClass());
}
}
// 2. 预编译表达式
$container->getParameterBag()->resolve();
// 3. 优化服务延迟加载
foreach ($container->getDefinitions() as $definition) {
$definition->setPublic(false);
if (!$definition->isLazy()) {
$definition->setLazy(true);
}
}
}
}
实际应用示例
1 复杂依赖注入
// services.yaml
services:
App\Service\OrderService:
arguments:
$connection: '@database_connection'
$eventDispatcher: '@event_dispatcher'
$logger: '@monolog.logger.order'
calls:
- ['setCache', ['@cache.app']]
tags:
- { name: 'monolog.logger', channel: 'order' }
// 注入配置参数
parameters:
orders.payment.timeout: 3600
orders.shipping.methods: ['standard', 'express', 'next_day']
services:
App\Service\PaymentService:
arguments:
$config:
timeout: '%orders.payment.timeout%'
methods: '%orders.shipping.methods%'
2 动态服务创建
// 工厂模式
class ServiceFactory
{
public static function create(string $type): ServiceInterface
{
switch ($type) {
case 'email':
return new EmailService();
case 'sms':
return new SmsService();
default:
throw new \InvalidArgumentException();
}
}
}
// services.yaml
services:
App\Service\NotificationService:
factory: ['App\Factory\ServiceFactory', 'create']
arguments:
- '%notification_type%'
性能优化技巧
// 1. 参数注入优化
services:
_defaults:
bind:
string $projectDir: '%kernel.project_dir%'
// 2. 服务懒加载
services:
App\Service\ExpensiveService:
lazy: true # 惰性加载直到使用时才实例化
// 3. 共享服务 vs 非共享服务
services:
App\Service\SharedService:
shared: true # 单例模式(默认)
App\Service\NonSharedService:
shared: false # 每次获取新实例
// 4. 常量注入
services:
App\Service\EnvAwareService:
arguments:
$env: !php/const App\Kernel::ENVIRONMENT
$debug: '%kernel.debug%'
容器调试命令
# 显示所有服务 php bin/console debug:container # 显示特定服务详情 php bin/console debug:container App\Service\MailService # 显示服务参数 php bin/console debug:container --parameters # 显示服务标签 php bin/console debug:container --tags # 显示自动装配服务 php bin/console debug:autowiring
最佳实践建议
// 1. 优先使用构造器注入
class UserService {
public function __construct(
private UserRepository $repository,
private LoggerInterface $logger
) {}
}
// 2. 避免循环依赖
// 坏示例
class A { public function __construct(B $b) {} }
class B { public function __construct(A $a) {} } // 循环依赖!
// 好 - 使用事件或服务定位器
class A {
public function __construct(EventDispatcherInterface $dispatcher) {}
}
// 3. 使用依赖注入而不是服务定位器
// 避免这样做
class BadClass {
public function doSomething() {
$container = $this->getContainer();
$service = $container->get('app.service');
}
}
// 应该这样做
class GoodClass {
public function __construct(
private MyService $service
) {}
}
Symfony 的 DI 容器提供了强大而灵活的服务管理机制,正确使用可以显著提升代码的可维护性和可测试性。