本文目录导读:

我来详细讲解ThinkPHP的依赖注入容器机制。
什么是依赖注入容器
基本概念
依赖注入(DI)是一种设计模式,容器则是管理依赖的中央注册表,ThinkPHP内置了完善的依赖注入容器,支持:
- 自动依赖解析
- 依赖注册
- 依赖管理
- 单例模式
容器的基本使用
1 获取容器实例
<?php
namespace app\index\controller;
use think\Container;
use think\facade\App;
class Index
{
// 方式1:通过全局函数
public function method1()
{
$container = app();
// 或者
$container = Container::getInstance();
}
// 方式2:通过门面
public function method2()
{
$container = App::getInstance();
}
}
2 基础绑定与解析
<?php
namespace app\common\service;
use think\Container;
class ContainerDemo
{
// 绑定接口到实现
public function bindInterface()
{
$container = Container::getInstance();
// 绑定接口到具体类
$container->bind('userService', UserService::class);
// 绑定闭包
$container->bind('logger', function() {
return new Logger('app');
});
// 绑定实例
$userService = new UserService();
$container->instance('userService', $userService);
}
// 解析依赖
public function resolveDependency()
{
$container = Container::getInstance();
// 通过名称解析
$userService = $container->make('userService');
// 通过类名解析
$logger = $container->make(Logger::class);
// 直接调用
$userService = app('userService');
}
}
构造函数注入
1 基础构造函数注入
<?php
namespace app\controller;
use app\common\service\UserService;
use app\common\service\OrderService;
use think\Request;
class UserController
{
protected $userService;
protected $orderService;
// 容器自动注入依赖
public function __construct(UserService $userService, OrderService $orderService)
{
$this->userService = $userService;
$this->orderService = $orderService;
}
public function index()
{
return $this->userService->getUserList();
}
}
2 复杂依赖注入
<?php
namespace app\common\service;
use think\Cache;
use think\Log;
use app\common\model\User;
use app\common\repository\UserRepository;
class UserService
{
protected $userRepository;
protected $cache;
protected $log;
// 多依赖自动注入
public function __construct(
UserRepository $userRepository,
Cache $cache,
Log $log
) {
$this->userRepository = $userRepository;
$this->cache = $cache;
$this->log = $log;
}
}
方法注入
<?php
namespace app\controller;
use think\Request;
use app\common\service\UserService;
class DemoController
{
// 方法参数自动注入
public function getUser(UserService $userService, Request $request)
{
$id = $request->get('id');
return $userService->getUser($id);
}
// 配合依赖标识
public function withDefault(Request $request)
{
// 控制器方法的Request会自动注入,无需手动实例化
return $request->param('name');
}
}
接口绑定与实现
<?php
namespace app\common\contracts;
// 定义接口
interface PaymentInterface
{
public function pay($amount);
public function refund($amount);
}
// 具体实现
namespace app\common\service;
use app\common\contracts\PaymentInterface;
class WechatPayment implements PaymentInterface
{
public function pay($amount)
{
return "微信支付: {$amount}元";
}
public function refund($amount)
{
return "微信退款: {$amount}元";
}
}
class AlipayPayment implements PaymentInterface
{
public function pay($amount)
{
return "支付宝支付: {$amount}元";
}
public function refund($amount)
{
return "支付宝退款: {$amount}元";
}
}
// 业务类
namespace app\common\service;
use app\common\contracts\PaymentInterface;
class PaymentService
{
protected $payment;
// 构造函数注入接口
public function __construct(PaymentInterface $payment)
{
$this->payment = $payment;
}
public function process($amount)
{
return $this->payment->pay($amount);
}
}
绑定配置
<?php
// 配置文件 config/di.php
return [
// 接口绑定
'bind' => [
'app\common\contracts\PaymentInterface' => 'app\common\service\WechatPayment',
'app\common\contracts\SMSSenderInterface' => 'app\common\service\AliyunSMS',
],
// 单例绑定
'singleton' => [
'app\common\service\CacheService',
'app\common\service\ConfigService',
],
];
依赖绑定示例
<?php
namespace app\common\provider;
use think\Container;
use app\common\contracts\PaymentInterface;
use app\common\service\WechatPayment;
use app\common\service\AlipayPayment;
class PaymentProvider
{
public static function register()
{
$container = Container::getInstance();
// 根据配置绑定接口
$paymentType = config('payment.default');
$container->bind(PaymentInterface::class, function() use ($paymentType) {
if ($paymentType === 'alipay') {
return new AlipayPayment();
}
return new WechatPayment();
});
// 绑定单例
$container->bind('paymentService', function() {
static $instance = null;
if ($instance === null) {
$instance = new PaymentService();
}
return $instance;
});
}
}
容器高级用法
1 依赖预处理
<?php
namespace app\common\service;
use think\Container;
class DatabaseService
{
public function boot()
{
$container = Container::getInstance();
// 定义工厂方法
$container->make('db.connection', function() {
$config = [
'type' => 'mysql',
'host' => env('DB_HOST', '127.0.0.1'),
'database' => env('DB_NAME', 'thinkphp'),
'username' => env('DB_USER', 'root'),
'password' => env('DB_PASS', '')
];
return new PDO(...);
});
}
}
2 容器的上下文绑定
<?php
namespace app\index\controller;
use think\Container;
class Index
{
public function contextBind()
{
$container = Container::getInstance();
// 上下文绑定
$container->bindTo(ApiController::class, 'logger', FileLogger::class);
$container->bindTo(CliController::class, 'logger', ConsoleLogger::class);
// 获取上下文实例
$apiLogger = $container->resolve(ApiController::class, 'logger');
$cliLogger = $container->resolve(CliController::class, 'logger');
}
}
依赖注入实战示例
1 业务逻辑层
<?php
namespace app\service;
use app\model\User;
use app\repository\UserRepository;
use think\Cache;
use think\Log;
class UserService
{
protected $userRepository;
protected $cache;
protected $log;
public function __construct(
UserRepository $userRepository,
Cache $cache,
Log $log
) {
$this->userRepository = $userRepository;
$this->cache = $cache;
$this->log = $log;
}
public function getUserInfo($id)
{
// 尝试从缓存获取
$cacheKey = 'user:' . $id;
$user = $this->cache->get($cacheKey);
if (!$user) {
$user = $this->userRepository->find($id);
$this->cache->set($cacheKey, $user, 3600);
}
$this->log->info("获取用户信息: {$id}");
return $user;
}
}
2 控制器使用
<?php
namespace app\controller;
use app\service\UserService;
use app\service\OrderService;
use think\Request;
use think\Response;
class UserController
{
protected $userService;
protected $orderService;
public function __construct(UserService $userService, OrderService $orderService)
{
$this->userService = $userService;
$this->orderService = $orderService;
}
public function info($id)
{
$user = $this->userService->getUserInfo($id);
$orders = $this->orderService->getUserOrders($id);
return Response::json([
'user' => $user,
'orders' => $orders
]);
}
}
3 门面模式
<?php
namespace app\facade;
use think\Facade;
class UserService extends Facade
{
protected static function getFacadeClass()
{
return 'app\service\UserService';
}
}
// 使用
namespace app\controller;
use app\facade\UserService;
class UserController
{
public function index()
{
// 通过门面访问
$users = UserService::getUserList();
// 等关于解耦
return $users;
}
}
性能优化建议
1 绑定单例
<?php
namespace app\common\service;
class CacheService
{
public function __construct()
{
// 初始化连接
}
}
// 注册为单例
app()->bind('cacheService', CacheService::class);
app()->make('cacheService'); // 只会实例化一次
2 延迟加载
<?php
namespace app\common\service;
use think\Container;
class LazyService
{
public function init()
{
$container = Container::getInstance();
// 延迟到需要时才实例化
$container->bind('heavyService', function() {
return new HeavyService(); // 懒加载
});
}
}
常见问题与解决方案
1 循环依赖
<?php
// 错误的循环依赖
class A {
public function __construct(B $b) {}
}
class B {
public function __construct(A $a) {} // 循环依赖
}
// 解决方案1:使用setter注入
class A {
public function setB(B $b) {
$this->b = $b;
}
}
// 解决方案2:使用容器方法
app()->bind(A::class, function() {
$a = new A();
$a->setB(app()->make(B::class));
return $a;
});
2 可选依赖
<?php
use think\Container;
class OptionalDependency
{
public function handle()
{
$container = Container::getInstance();
// 检查依赖是否存在
if ($container->has('optionalService')) {
$service = $container->make('optionalService');
}
// 或者设置默认值
$service = $container->make('optionalService', [
'default' => new DefaultService()
]);
}
}
最佳实践
- 接口绑定:总是使用接口绑定,便于替换和测试
- 构造函数注入:首选构造函数注入,确保依赖完整
- 缓存容器实例:适当使用单例减少资源消耗
- 依赖抽象:依赖抽象接口而不是具体实现
- 合理使用门面:门面提供简洁的静态调用但不会过度耦合
通过合理使用ThinkPHP的依赖注入容器,可以让你的项目更易于测试、维护和扩展。