modethirteen/opencontainer

PHP 依赖注入容器,请负责任地使用

2.1.0 2020-12-12 01:19 UTC

This package is auto-updated.

Last update: 2024-09-13 06:27:57 UTC


README

PHP 依赖注入容器,请负责任地使用。

github.com codecov.io Latest Stable Version Latest Unstable Version

关于

OpenContainer 是为了在具有完整功能的 PHP 开发环境中利用严格的类型检查而创建的,例如 JetBrains PHPStorm 或 PHP 7+ 的原生严格类型检查,当从集中式容器管理依赖项时。此外,它包含了一些关于反射和代理的实验,以避免在容器依赖链中引入循环依赖时出现的问题。

除了将依赖项公开为经过类型检查的类属性外,OpenContainer 还与 PSR-11 容器接口 兼容,以便与多个 PHP 框架进行互操作。

需求

  • PHP 7.4 (主要,2.x)

安装

使用 Composer。将 OpenContainer 添加到项目的两种方法。

从 composer CLI

./composer.phar require modethirteen/opencontainer

或将 modethirteen/opencontainer 添加到项目的 composer.json 文件中

{
    "require": {
        "modethirteen/opencontainer": "dev-main"
    }
}

dev-main 是主要开发分支。如果您在生产环境中使用 OpenContainer,建议您使用稳定版本。

假设您已设置 Composer 的自动加载器,OpenContainer 可以在 modethirteen\OpenContainer\ 命名空间中找到。

将 OpenContainer 添加到您的应用程序

只需实例化 OpenContainer 即可。

$container = new OpenContainer();

可注入类

可注入类在构建时通过注入容器进行实例化。在此示例中,Foo、Bar 和 Baz 都是容器中注册的类型。如果容器中注册的类型需要 Baz 的方法 doSomething(),Baz 必须首先从容器中获取它的依赖项 Foo 和 Bar(以及它们的依赖项,创建依赖树)。

class Baz {

  private Foo $foo;
  private Bar $bar;

  public function __construct(IContainer $container) {
    $this->foo = $container->Foo;
    $this->bar = $container->Bar;
  }
  
  public function doSomething() : string {
    return $this->foo->myMethod();
  }
}

注册类型

注册类型需要符号来标识从容器获取其实例化实例时的类型,以及构建的完全限定类名。

/**
 * setup the type as a virtual property so that IDE's that support type checking can take advantage
 *
 * @property Foo $Foo
 */
class MyContainer extends OpenContainer {
}

$container = new MyContainer();
$container->registerType('Foo', Foo::class);

// type checks will infer this object to be an instance of Foo
$instance = $container->Foo;

注册实例

注册实例需要符号来标识从容器获取实例时的实例,以及已创建的实例本身。注册实例在类型的构造函数无法满足可注入类的要求时很有用。

/**
 * setup the type as a virtual property so that IDE's that support type checking can take advantage
 *
 * @property Bar $Bar
 */
class MyContainer extends OpenContainer {
}

$container = new MyContainer();
$container->registerInstance('Bar', new Bar($dependency, $outside, $of, $container));

// type checks will infer this object to be an instance of Bar
$instance = $container->Bar;

注册构建器

注册构建器需要符号来标识从容器获取实例时的实例,以及一个闭包函数,在第一次获取时执行。注册构建器在创建实例之前必须执行一些专用步骤时很有用。

/**
 * setup the type as a virtual property so that IDE's that support type checking can take advantage
 *
 * @property Qux $Qux
 */
class MyContainer extends OpenContainer {
}

$container = new MyContainer();
$container->registerBuilder('Qux', function(MyContainer $container) : Qux {

  // builder functions only have one argument, access to the container itself
  return new Qux($container, $some, $other, $dependency);
});

// type checks will infer this object to be an instance of Qux
$instance = $container->Qux;

延迟容器

延迟容器试图使用反射和类代理来避免循环依赖。延迟容器返回代理,直到在代理上访问方法或属性时才实例化。此行为很有用,因为没有它,树中的每个依赖项在根依赖项首次实例化时都会实例化(无论这些下游依赖项最终是否会被使用)。如果不将依赖项实例化延迟到实际需要时,任何循环依赖都会返回空值、无限嵌套函数循环,或者在无法解决时引发 未定义属性 警告。

$container = (new OpenContainer)->toDeferredContainer();

// all methods on a deferred container are identical to a non-deferred container
$container->registerType('Plugh', Plugh::class);
$container->registerInstance('Plugh', new Plugh());

// closure function style builders require a return type, otherwise an OpenContainerCannotBuildDeferredInstanceException will be thrown 
$container->registerBuilder('Plugh', function(IContainer $container) : Plugh { ... });
$container->Plugh;