anonymous-php/simple-di

简单的依赖解析和注入容器

1.1.3 2018-05-03 13:48 UTC

This package is auto-updated.

Last update: 2024-09-08 02:05:34 UTC


README

实际上,这个库更多的是关于依赖容器,而不是自动装配,但别担心,自动装配是有的。您可以创建具有自动装配参数的类实例,并将依赖注入到调用的方法中。

历史

我非常喜欢PHP-DI,但当开始新的项目时,我意识到它需要另一种确定其定义和依赖的方法。我希望有尽可能简单的定义语法,同时具有强大但又不复杂的注入机制。所以我只是编写了自己的DI。

特性

我不想将任何定义包装在不必要的函数中,这些函数只是将此定义标记为可实例化的类。在编写代码时,我已经知道它是怎么回事,我想决定如何在我的应用程序中使用这些信息。

我的同事询问了我的库中的原始注入。我认为这不是一个好主意。只需为容器设置依赖关系,并获取所需值。自己控制这类值的类型。

兼容性

默认情况下,自动装配是禁用的。

安装

composer require anonymous-php/simple-di

方法

Container 实现了 \Psr\Container\ContainerInterface 接口,因此有两个方法: has($id),它按常规工作,以及 get($id),它可能具有与您首选库不同的行为。还有一个方法 set($id, $value),它确实如此。

get($id)

该方法响应原始值,唯一的例外是闭包。在闭包的情况下,库会通过注入其依赖关系来解析它。闭包可以返回任何原始值或任何您希望的类的实例。此方法会缓存解析的结果。

<?php

$container = new \Anonymous\SimpleDi\Container([
    'primitive' => 42,
    'wrapped-primitive' => function (\Psr\Container\ContainerInterface $c) {
        return (string)$c->get('primitive');
    },
]);

var_dump($container->get('primitive'), $container->get('wrapped-primitive'));

// int(42)
// string(2) "42"

instantiate($id, array $arguments = [], $instanceOf = null)

此方法创建特定类的实例。它尝试解析定义或在没有定义的情况下实例化提供的类。该方法在每次调用时都会创建一个新的实例。如果闭包作为参数提供,则 instantiate 也会每次都解析它。

<?php

interface I {}
class A implements I {}
class B implements I {}

$container = new \Anonymous\SimpleDi\Container([
    I::class => A::class,
    B::class => function () {
        return new B();
    },
]);

var_dump(
    $container->instantiate(I::class),
    $container->instantiate(A::class),
    $container->instantiate(B::class, [], I::class)
);

$container->instantiate('C');

/*

object(A)#4 (0) {
}
object(A)#5 (0) {
}
object(B)#7 (0) {
}
PHP Fatal error:  Uncaught Anonymous\SimpleDi\FactoryException Unresolvable dependency 'C'

*/

make($id, array $arguments = [], $recreate = false)

几乎与上一个相同,但具有缓存。这意味着您将在每次方法调用中获取相同的实例。如果使用相同的 $idinstantiate 之后调用 make,您将获得已缓存的类实例。

<?php

class A {}

$container = new \Anonymous\SimpleDi\Container();

var_dump(
    $container->instantiate(A::class),
    $container->make(A::class)
);

/*

object(A)#2 (0) {
}
object(A)#2 (0) {
}

*/

injectOn($callable, array $arguments = [])

将参数注入到提供的 实例 的方法中,并调用它。如果参数数组不包含调用方法等待的所有变量,则库会尝试解析它们。注意:闭包是一个具有 __invoke 方法的对象,因此您可以在它上使用 injectOn

<?php

class A {
    public function e($v) {
        return $v;
    }
}

class B { 
    public function strtoupper($v) {
        return strtoupper($v);
    }
}

$container = new \Anonymous\SimpleDi\Container();

var_dump(
    $container->injectOn([new A(), 'e'], ['v' => 'value1']),
    $container->injectOn(function (B $b, $v) { return $b->strtoupper($v); }, ['v' => 'value2'])
);

// string(5) "value1"
// string(5) "VALUE2"

call($callable, array $arguments = [])

几乎与 injectOn 相同,但它提供了解析和实例化提供类的可能性。

<?php

interface Filter
{
    public function __invoke($v);
}

class Upper implements Filter
{
    public function __invoke($v)
    {
        return strtoupper($v);
    }
}

interface Output
{
    public function __invoke($v);
}

class StdOutput implements Output
{
    public function __invoke($v)
    {
        echo $v, PHP_EOL;
    }
}

class Printer
{
    protected $filter;

    public function __construct(Filter $filter)
    {
        $this->filter = $filter;
    }

    public function out(Output $output, $value)
    {
        $filter = $this->filter;
        $output($filter instanceof Filter ? $filter($value) : $value);
    }
}

$container = new \Anonymous\SimpleDi\Container([
    Output::class => StdOutput::class,
    Filter::class => Upper::class,
]);

$container->call([Printer::class, 'out'], ['value' => 'Text to print 1']);
$container->call('Printer::out', ['value' => 'Text to print 2']);

// TEXT TO PRINT 1
// TEXT TO PRINT 2

待办事项

  • 文档
  • 测试
  • 性能测量