wlib / dibox

DiBox 是一个依赖注入容器。

v1.2.0 2023-12-17 23:12 UTC

This package is auto-updated.

Last update: 2024-09-18 00:46:06 UTC


README

DiBox 是一个依赖注入容器。它遵循 PSR-11 指令。

安装

composer require wlib/dibox

使用

use wlib\Di\DiBox;

$box = new DiBox();

实例化对象

容器可以用于简单地实例化对象

// Créer une instance de Foo\Bar
$bar = $box->make(Foo\Bar::class);

// Passer des arguments au constructeur
$bar = $box->make(Foo\Bar::class, ['a', 'b']); // indexés
$bar = $box->make(Foo\Bar::class, ['sGreetings' => 'Hello']); // nommés, ici, le constructeur attend l'entrée `$sGreetings`

通过容器的好处是能够自动解析构造函数所需的类

class Bar { public function __construct(public Baz $baz); }
class Baz {}

$bar = $box->make(Bar::class);

// $bar->baz sera une instance de Baz

声明依赖

实例化已经不错,但定义依赖更好,特别是为了构建应用程序

直接依赖

不一定最有用,但它是有效的

$box->bind(Foo\Bar::class);
$bar = $box->get(Foo\Bar::class); // instance de Foo\Bar

创建别名

为所有人取别名(或者整理容器,看你的需要)

$box->bind('MyBar', Foo\Bar::class);
$bar = $box->get('MyBar'); // toujours une instance de Foo\Bar mais depuis son p'tit nom

现有实例

如果需要

$bar = new Foo\Bar();
$box->bind('MyBar', $bar);
$samebar = $box->get('MyBar'); // toujours pareil !

创建关闭

或者 Closure 对专业人士来说。从这里开始,事情变得有趣,变得有意义。

$box->bind('MyBaz', function($box, $args)
{
	return new Foo\Baz($box->get('MyBar'));
});

$baz = $box->get('MyBaz'); // instance de Foo\Baz prête à bosser, classe non ?

所以,你面前展现出了无限的可能性!

标量值

你可以最多,也可以最少,你还可以在容器中存储简单的值

$box->bind('one.string', 'DiBox has all of a great one !');
$box->bind('one.integer', 2023);
$box->bind('one.array', [1, 2, 3]);

echo $box->get('one.string'));  // Affiche "DiBox has ...')
echo $box->get('one.integer')); // Affiche "2023"
echo $box->get('one.array'));   // Attention piège, ça affiche quoi ?

“ArrayAccess” 模式

容器实现了 ArrayAccess 接口

$box['make.b']   = function ($box, $args) { return new B(new A()); };
$box['integer']  = 4046;
$box['list']     = ['a', 'b', 'c'];
$box['class.a']  = A::class;

$b        = $box['make.b'];  // instance de B
$iInteger = $box['integer']; // 4096
$aList    = $box['list'];    // cf. 5 lignes au dessus
$a        = $box['class.a']; // bon, vous maîtrisez normalement

因此,你可以使用 isset()unset()

unset($box['class.a']);
isset($box['class.a']); // >> false

共享依赖(单例)

你可以根据需要共享依赖:单例模式(但比单例模式更好,因为你知道即使它很有用,创建真正的单例也不总是最佳实践)

class Counter
{
    protected $count = 0;
    
    public function increment(): int
    {
        return $this->count++;
    }
}

$box->singleton(Counter::class);

echo $box->get(Counter::class)->increment(); // 0
echo $box->get(Counter::class)->increment(); // 1
echo $box->get(Counter::class)->increment(); //	2

其他方法

以下是一些需要了解的方法

$box->has('MyBar');    // pour vérifier la présense d'une dépendance
$box->remove('MyBar'); // pour retirer cette dépendance que vous ne voulez plus voir
$box->empty();         // pour vider le conteneur

依赖提供者

你还在这里?声明许多依赖并填充容器是很好,但你可能正在开发一个可能不知道将如何处理所有依赖的应用程序,或者你只是想在你不同的命名空间/包中组织这一切。

因此,你需要创建提供者,它们将负责在容器中注入它们的依赖。

因此,现在是时候实现 wlib\Di\DiBoxProvider 合约了。

// Exemple (classique ?) d'un fournisseur des services HTTP d'une application
class HttpProvider implements DiBoxProvider
{
	public function provide(DiBox $box)
	{
		$box->bind('http.request', function($box, $args)
		{
			return MyApp\Http\Request();
		});

		$box->bind('http.response', function($box, $args)
		{
			return MyApp\Http\Response($box['http.request']);
		});
	}
}

// Et pour le fournir au conteneur, rien de plus simple :
$box->register(HttpProvider::class);

$response = $box->get('http.response'); // Et vous avez une réponse HTTP prête à servir vos applications / API

好了,你已经掌握了!现在轮到你发挥作用了。

异常

如果出现故障,无论是故意的还是意外的,DiBox 可能会引发以下异常

  • wlib\Di\DiException:在容器不高兴的时候抛出
  • wlib\Di\DiNotFoundException:符合 PSR-11,如果你尝试访问不存在的依赖,则会抛出

单元测试

不要犹豫,查看 /tests/Unit/DiBoxTest.php 文件,它将为您提供有关如何使用 DiBox 的额外技术细节。

单元测试使用了 Pest 库。