xp-forge/inject

XP 框架的依赖注入

v6.0.0 2024-03-24 11:29 UTC

README

Build status on GitHub XP Framework Module BSD Licence Requires PHP 7.4+ Supports PHP 8.0+ Latest Stable Version

inject 包包含了 XP 框架的依赖注入 API。它的入口类是 "Injector"。

绑定

可以使用注入器的 bind() 方法将值绑定到注入器上。它接受要绑定的类型、可选名称和以下不同场景

  • 绑定一个类:最典型的用法,将接口绑定到其具体实现。
  • 绑定一个实例:通过将类型绑定到现有实例,可以创建一个 单例 模型。
  • 绑定一个提供者:如果需要更复杂的代码来创建实例,可以绑定到提供者。
  • 绑定一个命名查找:如果我们想控制类型的绑定查找,我们可以绑定到 Named 实例。
use inject\{Injector, Bindings};
use com\example\{Report, HtmlReport, Storage, InFileSystem};

// Manually
$injector= new Injector(Bindings::using()
  ->typed(Report::class, HtmlReport::class)
  ->singleton(Storage::class, new InFileSystem('.'))
  ->named('title', 'Report title')
);

// Reusable via Bindings instances
class ApplicationDefaults extends Bindings {

  public function configure($injector) {
    $injector->bind(Report::class, HtmlReport::class);
    $injector->bind(Storage::class, new InFileSystem('.'));
    $injector->bind('string', 'Report title', 'title');
  }
}

$injector= new Injector(new ApplicationDefaults());

实例创建

请注意:"injector.get() 是新的 'new'"。要创建对象和执行注入,请使用注入器的 get() 方法而不是使用 new 关键字或工厂。

use inject\Injector;

$injector->bind(Report::class, HtmlReport::class);

// Explicit binding: Lookup finds binding to HtmlReport, creates instance.
$instance= $injector->get(Report::class);

// Implicit binding: No previous binding, TextReport instantiable, thus created.
$instance= $injector->get(TextReport::class);

通常不需要手动调用,而是使用注入

注入

通过查看类型的构造函数来执行注入。根据给定的类型提示传递绑定的值。

class ReportImpl implements Report {

  public function __construct(ReportWriter $writer) { ... }
}

如果 PHP 类型系统不够简洁,可以通过使用参数属性来提供类型。如果绑定的值的名称与参数名称不同,可以提供名称参数。

use inject\Inject;

class ReportImpl implements Report {

  public function __construct(
    ReportWriter $writer,
    Format $format,
    #[Inject(type: 'string[]', name: 'report-titles')]
    $titles
  ) { ... }
}

当遇到所需的参数但没有为该参数绑定值时,会引发 inject.ProvisionException

class ReportWriter implements Writer {

  public function __construct(Storage $storage) { ... }
}

$injector= new Injector();
$report= $injector->get(ReportWriter::class);  // *** Storage not bound

不支持方法和字段注入。

配置

如上所示,可以使用绑定而不是手动执行连接。您可能希望将应用程序的一些设置配置在外部,而不是硬编码。为此请使用 inject.ConfiguredBindings 类。

$injector= new Injector(
  new ApplicationDefaults(),
  new ConfiguredBindings(new Properties('etc/app.ini'))
);

这些 INI 文件的语法很简单

web.session.Sessions=web.session.InFileSystem("/tmp")
name="Application"

提供者

提供者允许实现延迟加载语义。绑定到注入器的每个类型也可以通过提供者检索。调用其 get() 方法将实例化它。

$provider= $injector->get('inject.Provider<com.example.writers.ReportWriter>');

// ...later on
$instance= $provider->get();

命名查找

如果需要控制查找,我们可以绑定 Named 实例。

use inject\{Injector, Named, InstanceBinding};
use com\example\Value;

$inject= new Injector();
$inject->bind(Value::class, new class() extends Named {
  public function provides($name) { return true; }
  public function binding($name) { return new InstanceBinding(new Value($name)); }
});

$value= $inject->get(Value::class, 'default');  // new Value("default")