依赖注入 #
一、依赖注入概述 #
1.1 什么是依赖注入 #
依赖注入是一种设计模式,将依赖从外部注入,而不是在类内部创建。
text
┌─────────────────────────────────────────────────────┐
│ 依赖注入 vs 传统方式 │
├─────────────────────────────────────────────────────┤
│ │
│ 传统方式: │
│ class UserService { │
│ private $repository = new UserRepository(); │
│ } │
│ │
│ 依赖注入: │
│ class UserService { │
│ public function __construct( │
│ private UserRepository $repository │
│ ) {} │
│ } │
│ │
└─────────────────────────────────────────────────────┘
1.2 依赖注入优势 #
| 优势 | 说明 |
|---|---|
| 解耦 | 类不依赖具体实现 |
| 可测试 | 易于模拟依赖 |
| 灵活 | 可轻松替换实现 |
| 可维护 | 依赖关系清晰 |
二、构造函数注入 #
2.1 基本用法 #
php
<?php
namespace App\Service;
use App\Repository\UserRepository;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
class UserService
{
public function __construct(
private EntityManagerInterface $entityManager,
private UserRepository $userRepository,
private LoggerInterface $logger
) {}
}
2.2 必需依赖 #
php
<?php
class OrderService
{
public function __construct(
private OrderRepository $orderRepository,
private PaymentService $paymentService
) {
if (!$orderRepository) {
throw new \InvalidArgumentException('OrderRepository is required');
}
}
}
2.3 可选依赖 #
php
<?php
class NotificationService
{
private ?LoggerInterface $logger;
public function __construct(
private MailerInterface $mailer,
?LoggerInterface $logger = null
) {
$this->logger = $logger;
}
public function send(string $to, string $subject, string $body): void
{
$this->mailer->send($to, $subject, $body);
$this->logger?->info("Email sent to $to");
}
}
三、Setter注入 #
3.1 基本用法 #
php
<?php
namespace App\Service;
use Psr\Log\LoggerInterface;
use Symfony\Contracts\Service\Attribute\Required;
class EmailService
{
private ?LoggerInterface $logger = null;
#[Required]
public function setLogger(LoggerInterface $logger): void
{
$this->logger = $logger;
}
public function send(string $to, string $content): void
{
$this->logger?->info("Sending email to $to");
}
}
3.2 配置Setter注入 #
yaml
# config/services.yaml
services:
App\Service\EmailService:
calls:
- setLogger: ['@logger']
- setFromEmail: ['noreply@example.com']
四、属性注入 #
4.1 使用#[Required]属性 #
php
<?php
namespace App\Service;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Contracts\Service\Attribute\Required;
class ReportService
{
#[Required]
public LoggerInterface $logger;
public function generate(): string
{
$this->logger->info('Generating report');
return 'Report content';
}
}
五、自动装配 #
5.1 启用自动装配 #
yaml
# config/services.yaml
services:
_defaults:
autowire: true
autoconfigure: true
App\:
resource: '../src/'
5.2 自动装配原理 #
php
<?php
// 自动装配会根据类型提示自动注入
class UserService
{
// 自动注入 UserRepository
public function __construct(
private UserRepository $userRepository
) {}
}
// 等同于手动配置
services:
App\Service\UserService:
arguments:
$userRepository: '@App\Repository\UserRepository'
5.3 禁用自动装配 #
yaml
# config/services.yaml
services:
App\Service\ManualService:
autowire: false
arguments:
$dependency: '@App\Service\Dependency'
六、接口注入 #
6.1 接口定义 #
php
<?php
namespace App\Interface;
interface PaymentGatewayInterface
{
public function charge(float $amount): bool;
public function refund(string $transactionId): bool;
}
6.2 接口实现 #
php
<?php
namespace App\Service;
use App\Interface\PaymentGatewayInterface;
class StripeGateway implements PaymentGatewayInterface
{
public function charge(float $amount): bool
{
return true;
}
public function refund(string $transactionId): bool
{
return true;
}
}
class PayPalGateway implements PaymentGatewayInterface
{
public function charge(float $amount): bool
{
return true;
}
public function refund(string $transactionId): bool
{
return true;
}
}
6.3 配置接口别名 #
yaml
# config/services.yaml
services:
App\Interface\PaymentGatewayInterface: '@App\Service\StripeGateway'
6.4 使用接口 #
php
<?php
class PaymentService
{
public function __construct(
private PaymentGatewayInterface $gateway
) {}
public function processPayment(float $amount): bool
{
return $this->gateway->charge($amount);
}
}
七、绑定参数 #
7.1 全局绑定 #
yaml
# config/services.yaml
services:
_defaults:
bind:
$projectDir: '%kernel.project_dir%'
$environment: '%kernel.environment%'
$debug: '%kernel.debug%'
App\Service\ConfigService:
arguments:
$siteName: '%app.site_name%'
7.2 使用绑定参数 #
php
<?php
namespace App\Service;
class FileService
{
public function __construct(
private string $projectDir,
private string $environment,
private bool $debug
) {}
public function getUploadPath(): string
{
return $this->projectDir . '/var/uploads';
}
}
八、#[Autowire]属性 #
8.1 注入服务 #
php
<?php
use Symfony\Component\DependencyInjection\Attribute\Autowire;
class UserService
{
public function __construct(
#[Autowire(service: 'logger')]
private LoggerInterface $logger,
#[Autowire('%kernel.project_dir%')]
private string $projectDir
) {}
}
8.2 注入环境变量 #
php
<?php
class ApiService
{
public function __construct(
#[Autowire(env: 'API_KEY')]
private string $apiKey,
#[Autowire(env: 'API_TIMEOUT')]
private int $timeout = 30
) {}
}
8.3 注入参数 #
php
<?php
class ConfigService
{
public function __construct(
#[Autowire('%app.items_per_page%')]
private int $itemsPerPage,
#[Autowire('%app.supported_locales%')]
private array $supportedLocales
) {}
}
九、服务定位器 #
9.1 使用服务定位器 #
php
<?php
namespace App\Service;
use Symfony\Component\DependencyInjection\ServiceLocator;
class HandlerService
{
public function __construct(
private ServiceLocator $handlers
) {}
public function handle(string $type): void
{
if ($this->handlers->has($type)) {
$handler = $this->handlers->get($type);
$handler->process();
}
}
}
9.2 配置服务定位器 #
yaml
# config/services.yaml
services:
App\Service\HandlerService:
arguments:
$handlers:
type1: '@App\Handler\Type1Handler'
type2: '@App\Handler\Type2Handler'
type3: '@App\Handler\Type3Handler'
十、惰性服务 #
10.1 配置惰性服务 #
yaml
# config/services.yaml
services:
App\Service\HeavyService:
lazy: true
10.2 使用惰性代理 #
php
<?php
use Symfony\Component\DependencyInjection\Attribute\AutowireLazy;
class ConsumerService
{
public function __construct(
#[AutowireLazy]
private HeavyService $heavyService
) {}
public function process(): void
{
// 只有实际调用时才初始化
$this->heavyService->doSomething();
}
}
十一、编译器传递 #
11.1 创建编译器传递 #
php
<?php
namespace App\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
class CustomCompilerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container): void
{
if (!$container->hasDefinition('app.handler_chain')) {
return;
}
$definition = $container->getDefinition('app.handler_chain');
$taggedServices = $container->findTaggedServiceIds('app.handler');
foreach ($taggedServices as $id => $tags) {
$definition->addMethodCall('addHandler', [$id]);
}
}
}
11.2 注册编译器传递 #
php
<?php
namespace App;
use App\DependencyInjection\Compiler\CustomCompilerPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class AppBundle extends Bundle
{
public function build(ContainerBuilder $container): void
{
parent::build($container);
$container->addCompilerPass(new CustomCompilerPass());
}
}
十二、总结 #
本章学习了:
- 依赖注入概念
- 构造函数注入
- Setter注入
- 属性注入
- 自动装配
- 接口注入
- 绑定参数
- #[Autowire]属性
- 服务定位器
- 惰性服务
- 编译器传递
下一章将学习 服务配置。
最后更新:2026-03-28