p810/ioc-container

一个依赖注入容器,可以使用PHP的Reflection API自动连接你的对象

1.1.0 2019-05-14 14:59 UTC

This package is auto-updated.

Last update: 2024-09-13 09:40:04 UTC


README

一个依赖注入容器,可以使用PHP的Reflection API自动连接你的对象

入门

此包可通过Packagist获得。

$ composer require p810/ioc-container --no-dev

p810\Container\Resolver描述了包含自动解决(自动连接)代码库中类功能的任何类。p810\Container\Container是一个抽象类,可以用作解析器的基类,为p810\Container\Entry实例提供存储功能,该实例是一个值对象,用于在容器中描述类。

此包附带默认解析器是p810\Container\ReflectionContainer,它使用Reflection扩展

将类添加到容器中

您可以使用p810\Container\Container::set()将类添加到容器中,提供完全限定的类名。这将返回您的类的p810\Container\Entry实例

$container->set(Foo::class);

您可以通过传递一个可调用的值作为第二个参数来指定任何给定类的自定义工厂。默认情况下,使用p810\Container\ReflectionContainer::resolve()。此方法将传递您的类的依赖项到容器中进行自动解决,这是一个称为自动连接的过程。

💡 注意:任何构造函数中包含非对象参数的类必须通过容器返回的p810\Container\Entry实例显式定义这些参数。这将在下面进行说明,在“指定参数的默认值”下。

向容器中添加单例

如果您希望条目始终返回一个特定对象,则可以将该对象作为p810\Container\Container::set()的第三个参数传递,或者调用p810\Container\Container::singleton()

$instance = new Foo(new Bar);

// this:
$container->set(Foo::class, $factory = null, $instance);

// is the same as this:
$container->singleton(Foo::class, $instance);

对于您的类要由容器解决,提供实例可能通过省略第二个参数或将其设置为null来跳过。

可以将可调用的值作为第三个参数传递,用作实例化单例的工厂。如果尚未传递实例,则将使用此。

第四个参数$resolveNow是一个可选的布尔值,将告诉容器是延迟实例化直到对象被请求,还是立即执行。默认情况下,设置为延迟实例化。

// this will trigger a call to ReflectionContainer::resolve() when Foo is requested:
$container->singleton(Foo::class);

// this will invoke the given anonymous function when Foo is requested:
$container->singleton(Foo::class, null, function () use ($bar): Foo {
    return new Foo($bar);
});

// this will invoke the given callback immediately:
$container->singleton(Foo::class, null, function (): Foo {
    return new Foo(new Bar);
}, true);

从容器中获取对象

可以通过调用p810\Container\Container::get()从容器中解决一个类。解析器将尝试自动解决它在类的构造函数中找到的任何类型提示的类,无论是在方法签名中还是在其docblock中的@param注释中。

class Foo {
    /**
     * @param Bar $bar
     * @param Bam $bam
     */
    function __construct(Bar $bar, $bam) {
        $this->bar = $bar;
        $this->bam = $bam;
    }
}

$foo = $container->get(Foo::class);

可以在解决类的名称之后传递默认参数给p810\Container\Container::get()。如果给定的唯一参数是关联数组,则将其视为命名参数的字典;否则将按数字查找值。

// this:
$foo = $container->get(Foo::class, [
    'bam' => new Bam,
    'bar' => new Bar
]);

// is the same as this:
$foo = $container->get(Foo::class, new Bar, new Bam);

也可以将参数值绑定到给定类的p810\Container\Entry实例。

指定参数的默认值

p810\Container\Entry::param()允许您通过名称绑定构造函数的参数值

class Bam {
    function __construct(string $message) {
        $this->message = $message;
    }
}

$entry = $container->set(Bam::class);

$entry->param('message', 'Hello world!');

您还可以使用复数对应物p810\Container\Entry::params()通过一个调用设置多个参数,通过传递一个关联数组

class Quux {
    function __construct(string $greeting, string $subject) {
        $this->message = \ucfirst($greeting) . ' ' . $subject . '!';
    }
}

$entry = $container->set(Quux::class);

$entry->params([
    'greeting' => 'hello',
    'subject'  => 'world'
]);

将特定类绑定到接口

容器可以被配置为在通过 p810\Container\Container::bind() 调用一个给定接口时返回一个特定类的对象。提供接口及其实现者的完全限定类名。

interface Baz {
    public function sayHello(string $subject): string;
}

class Bem implements Baz {
    public function sayHello(string $subject): string {
        return "Hello $subject!";
    }
}

$container->bind(Baz::class, Bem::class);

var_dump($container->get(Baz::class) instanceof Bem::class); //=> bool: true

💡 注意: 如果你传递给 p810\Container\Container::bind() 的类尚未在容器中注册,它将使用默认设置进行注册。若要自定义类的配置,你必须先注册它,然后再将其绑定到接口。

许可证

本软件包是在 MIT 许可证 下免费和开源的。