首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >PHP 依赖注入容器和服务定位器

PHP 依赖注入容器和服务定位器

作者头像
Tinywan
发布2026-07-01 12:04:54
发布2026-07-01 12:04:54
920
举报
文章被收录于专栏:开源技术小栈开源技术小栈

依赖注入之-容器

依赖注入(Dependency Injection,DI)容器就是一个对象,它知道怎样初始化并配置对象及其依赖的所有对象。注册会用到一个依赖关系名称和一个依赖关系的定义。依赖关系名称可以是一个类名,一个接口名或一个别名。依赖关系的定义可以是一个类名,一个配置数组,或者一个 PHP 回调。

常见注入方式

1、构造方法注入(Constructor Injection)

在参数类型提示的帮助下,DI 容器实现了构造方法注入。当容器被用于创建一个新对象时,类型提示会告诉它要依赖什么类或接口。容器会尝试获取它所依赖的类或接口的实例,然后通过构造器将其注入新的对象。例如:

代码语言:javascript
复制
class Foo {
    public function __construct(Bar $bar) {
    }
}
$foo = $container->get('Foo');
// 上面的代码等价于:
$bar = new Bar;
$foo = new Foo($bar);

2、方法注入(Method Injection)

通常,类的依赖关系传递给构造函数,并且在整个生命周期中都可以在类内部使用。通过方法注入,可以提供仅由类的单个方法需要的依赖关系,并将其传递给构造函数可能不可行,或者可能会在大多数用例中导致太多开销。

代码语言:javascript
复制
class MyClass extends \yii\base\Component {
    public function __construct(/*Some lightweight dependencies here*/, $config = []) {
        // ...
    }
    public function doSomething($param1, \my\heavy\Dependency $something) {
        // do something with $something
    }
}

3、Setter 和属性注入(Setter and Property Injection)

Setter 和属性注入是通过配置提供支持的。当注册一个依赖或创建一个新对象时,你可以提供一个配置,该配置会提供给容器用于通过相应的 Setter 或属性注入依赖。例如:

代码语言:javascript
复制
use yii\base\BaseObject;

class Foo extends BaseObject {
    public $bar;
    private $_qux;
    publicfunction getQux() {
        return$this->_qux;
    }
    publicfunction setQux(Qux $qux) {
        $this->_qux = $qux;
    }
}
$container->get('Foo', [], [
    'bar' => $container->get('Bar'),
    'qux' => $container->get('Qux'),
]);

直接注入类到容器中

TP框架绑定一个类到容器中(第一个参数直接传入类名)

1、使用容器
代码语言:javascript
复制
// 绑定类库标识
Container::getInstance()->bindTo(GameService::class);
// 自动实例化
$obj = Container::get(GameService::class);
// 快速调用
halt($obj->test());
2、使用助手函数
代码语言:javascript
复制
// 绑定类库标识
bind(GameService::class);
// 快速调用(自动实例化)
$obj = app(GameService::class);
halt($obj);

Yii2.0 注册一个同类名一样的依赖关系

代码语言:javascript
复制
$container = new \yii\di\Container;
// 注册一个同类名一样的依赖关系,这个可以省略。
$container->set(GameService::class);

绑定类标识

TP框架可以对已有的类库绑定一个标识(唯一),便于快速调用

1、使用容器
代码语言:javascript
复制
// 绑定类库标识
Container::getInstance()->bindTo('game_service2', GameService::class);
// 快速调用(自动实例化)
$obj = Container::get('game_service2');
halt($obj);
2、使用助手函数
代码语言:javascript
复制
// 绑定类库标识
bind('game_service', GameService::class);
// 快速调用(自动实例化)
$obj = app('game_service');
// 带参数实例化调用
$obj = app('game_service', ['file']);
halt($obj->test());

Yii2.0 注册一个别名

代码语言:javascript
复制
$container = new \yii\di\Container;
$container->set('foo', 'yii\db\Connection');
// 创建一个 Connection 实例
$obj = $container->get('foo');

绑定闭包

TP框架使用

代码语言:javascript
复制
// 使用助手函数
bind('sayHello', function ($name) {
    return 'hello,' . $name;
});
echo app('sayHello', ['thinkphp']);

// 使用容器
Container::getInstance()->bindTo('sayTinywan', function ($age) {
    return 'Tinywan is ' . $age;
});
echo Container::get('sayTinywan', [24]);

Yii2.0 注册一个 PHP 回调

代码语言:javascript
复制
// 每次调用 $container->get('db') 时,回调函数都会被执行。
$container->set('db', function ($container, $params, $config) {
    return new \yii\db\Connection($config);
});

类绑定到接口

代码语言:javascript
复制
// 绑定 think\LoggerInterface 接口实现到 think\Log
bind('think\LoggerInterface', 'think\Log');

使用接口作为依赖注入的类型:

代码语言:javascript
复制
<?php
namespace app\index\controller;
use think\LoggerInterface;

class Index {
    public function hello(LoggerInterface $log) {
        $log->record('hello,world!');
    }
}

或者使用容器:

代码语言:javascript
复制
// 绑定 app\driver\DriverInterface 接口实现到 app\driver\YoungDriver
$driver = Container::getInstance()->bindTo(DriverInterface::class, YoungDriver::class);
$car = Container::get(Car::class, [$driver]);
var_dump($car->run());

依赖注入之-服务定位器

服务定位器是一个了解如何提供各种应用所需的服务(或组件)的对象。在服务定位器中,每个组件都只有一个单独的实例,并通过 ID 唯一地标识。用这个 ID 就能从服务定位器中得到这个组件。

TP框架使用

1、配置文件 provider.php

系统会自动批量绑定类库到容器中:

代码语言:javascript
复制
// 应用容器绑定定义
return [
    'game_player' => \app\common\repositories\player\Game::class,
    'random' => \app\common\repositories\game\RandomGroup::class,
];

2、那类玩家在玩那个游戏

代码语言:javascript
复制
// 声明那类玩家
Container::getInstance()->bindTo(PlayerInterface::class, TeacherPlayer::class);
// 要玩那个游戏
$game = app('random');
// 获取玩家实例
$player = app('game_player');
// 玩家开始玩什么游戏
halt($player->play($game));

3、携带参数

代码语言:javascript
复制
// 声明那类玩家
Container::getInstance()->bindTo(PlayerInterface::class, StudentPlayer::class);
// 要玩那个游戏
$game = app('random');
// 获取玩家实例
$parms = ['caode' => 200, 'name' => 'Tinywan'];
$player = app('game_player', ['ddd']);
// 玩家开始玩什么游戏
halt($player->play($game, $parms));
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-11-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 开源技术小栈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 依赖注入之-容器
    • 常见注入方式
      • 1、构造方法注入(Constructor Injection)
      • 2、方法注入(Method Injection)
      • 3、Setter 和属性注入(Setter and Property Injection)
    • 直接注入类到容器中
      • TP框架绑定一个类到容器中(第一个参数直接传入类名)
      • Yii2.0 注册一个同类名一样的依赖关系
    • 绑定类标识
      • TP框架可以对已有的类库绑定一个标识(唯一),便于快速调用
      • Yii2.0 注册一个别名
    • 绑定闭包
      • TP框架使用
      • Yii2.0 注册一个 PHP 回调
    • 类绑定到接口
  • 依赖注入之-服务定位器
    • TP框架使用
      • 1、配置文件 provider.php
      • 2、那类玩家在玩那个游戏
      • 3、携带参数
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档