PHP项目ThinkPHP依赖注入容器

wen PHP项目 3

本文目录导读:

PHP项目ThinkPHP依赖注入容器

  1. 什么是依赖注入容器
  2. 容器的基本使用
  3. 构造函数注入
  4. 方法注入
  5. 接口绑定与实现
  6. 绑定配置
  7. 依赖绑定示例
  8. 容器高级用法
  9. 依赖注入实战示例
  10. 性能优化建议
  11. 常见问题与解决方案
  12. 最佳实践

我来详细讲解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()
        ]);
    }
}

最佳实践

  1. 接口绑定:总是使用接口绑定,便于替换和测试
  2. 构造函数注入:首选构造函数注入,确保依赖完整
  3. 缓存容器实例:适当使用单例减少资源消耗
  4. 依赖抽象:依赖抽象接口而不是具体实现
  5. 合理使用门面:门面提供简洁的静态调用但不会过度耦合

通过合理使用ThinkPHP的依赖注入容器,可以让你的项目更易于测试、维护和扩展。

抱歉,评论功能暂时关闭!