undercloud/reservoir

Reservoir - PHP DI (依赖注入)

v0.2.0-alpha 2020-01-15 08:34 UTC

This package is auto-updated.

Last update: 2024-09-17 04:41:09 UTC


README

Build Status

受Laravel服务容器的启发

在软件工程中,依赖注入是一种技术,其中一个对象(或静态方法)提供另一个对象的依赖。依赖是一个可用的对象(一个服务)。

安装

composer require undercloud/reservoir

用法

创建容器实例

$di = new Reservoir\Di;

实例

您可以使用instance方法将现有的对象实例绑定到容器中。后续对容器的调用将始终返回该实例

$di->instance('foo', new Bar);

单例

singleton方法将一个类或接口绑定到容器中,该类或接口应该只被解析一次。一旦解析了单例绑定,后续对容器的调用将返回相同的对象实例

$di->singleton('database', function(Reservoir\Di $di) {
    return new DataBase(
        $di->make('settings')->driver,
        $di->make('settings')->user,
        $di->make('settings')->pass
    );
});

绑定

我们可以使用bind方法注册一个绑定,传递我们想要注册的类或接口名称以及一个返回该类实例的Closure

$di->bind('autoloader', function(Reservoir\Di $di) {
    return new Autoloader(
        $di->make('include-path')
    );
});

服务容器的一个非常强大的功能是它能够将一个接口绑定到一个特定的实现

namespace App\Database;

class Driver
{
    public function __construct(Abstract $driver)
    {
        ...
    }
}

$di->bind('App\Database\Abstract', 'App\Database\Mysql');

// App\Database\Mysql
$di->make('App\Database\Driver')

别名

为了同时支持类/接口和短名称,请使用alias

$di->alias('db', 'App\Database\Mysql');

装饰器

如果您想在容器中添加额外的功能到现有的绑定,请使用decorator方法

$di->decorator('database', function($db, Reservoir\Di $di) {
    $decorator = new DatabaseDecorator($db);

    return $decorator;
});

分支

有时可能需要在容器中创建现有实体的副本,可以通过fork方法来实现,从容器中检索现有绑定并将其克隆

$di->fork('db', function($db, Reservoir\Di $di) {
    $mongo = $db->setDriver('mongo');

    $di->instance('mongo', $mongo);
})

解析

make

简单实体提取

$di->make('foo');

解析类

$di->make('App\Database\Mysql');

解析方法

$di->make('Foo::bar');

$di->make(['Foo', 'bar']);

$di->make([$foo, 'bar']);

魔法__invoke

class Foo 
{
    public function __invoke(Bar $bar)
    {
        /* ... */
    }
}

$foo = new Foo;

$di->make($foo);

通过Closure提取实体

$di->make(function(Foo $foo, Bar $bar){
    /* ... */
})

额外参数

make方法有一个第二个$additional参数,有助于传递不在容器中的参数

// DateTime constructor's prototype
// public __construct ([ string $time = "now" [, DateTimeZone $timezone = NULL ]] )

$this->di->make('DateTime', ['time' => $date])

makes

检索实体列表

// [Foo, Bar]
list($foo, $bar) = $di->makes('foo', 'bar');

// [Foo, Bar]
list($foo, $bar) = $di->makes(['foo', 'bar']);

绑定原始数据

有时,您可能有一个接收一些注入类但还需要注入原始数据(如整数)的类。您可以使用上下文绑定轻松注入类可能需要的任何值

$di->when('DateTime')
    ->needs('$time')
    ->give($timestamp);

上下文绑定

有时,您可能有两个使用相同接口的类,但您希望将不同的实现注入到每个类中

$di->when('DateTime')
    ->needs('DateTimeZone')
    ->give(function () {
        return new DateTimeZone("EDT");
    });

ServiceProvider

所有服务提供程序都扩展了Reservoir\ServiceProvider类。大多数服务提供程序包含一个register方法

use Reservoir\Di;
use Reservoir\ServiceProvider;

class DatabaseServiceProvider extends ServiceProvider
{
    public function register()
    {
        $this->di->singleton('db', function(Di $di) {
            return new DatabaseConnection(
                $di->make('host'),
                $di->make('user'),
                $di->make('pass')
            );
        });
    }
}

注册服务提供程序

$di->register('DatabaseServiceProvider');

延迟提供程序

如果您的提供程序仅注册服务容器中的绑定,您可以选择在注册的绑定实际需要时才注册它。延迟加载此类提供程序将提高应用程序的性能,因为它不需要在每次请求时从文件系统中加载

use Reservoir\Di;
use Reservoir\ServiceProvider;

class DatabaseServiceProvider extends ServiceProvider
{
    public $deferred = true;

    public function provides()
    {
        return ['db'];
    }

    public function register()
    {
        ...
    }
}

注册延迟服务提供程序

$di->register('DatabaseServiceProvider');

工具

has

检查是否注册了键

// true
$di->has('foo')

keys

获取所有注册的键

// ['foo','bar',...]
$di->keys()

forget

移除实例

$di->forget('foo')

flush

清除所有注册的键

$di->flush()