substancephp/container

一个用于PHP的PSR-11 IoC容器

v0.6.0 2024-09-29 21:46 UTC

This package is auto-updated.

Last update: 2024-09-30 12:32:16 UTC


README

CI

概述

substancephp/container 是一个PHP的依赖注入包。它提供以下功能:

  • 实现 PSR-11容器接口 的容器类
  • 容器继承机制
  • 使用类型提示或属性自动将参数注入闭包中
  • 可选的自动装配

安装

composer require substancephp/container

用法

以下是一个示例代码段,展示如何使用 SubstancePHP\Container 类定义注入的依赖项。

use Laminas\Diactoros\ServerRequestFactory;
use Psr\Http\Message\ServerRequestInterface;
use SubstancePHP\Container\Container;
use SubstancePHP\Container\Inject;

// Initialize a `Container` instance from an array. The keys are strings (typically, but not necessarily,
// class names), and the values are callbacks telling the container how to construct that dependency.
$container = Container::from([

    // Example of "manual" definition
    Foo::class => fn () => new Foo('example', 'constructor', 'parameters'),
    
    // The callback optionally takes a parameter, referring to the Container instance itself.
    // This can be used to get other dependencies to be used in the callback.
    BarInterface::class => fn (Container $c) => new BarImplementation($c->get(Foo::class)),
    
    // The static `Container::autowire` method can be referenced to as a closure. It will arrange for the
    // construction of the given dependency instance using reflection on its constructor parameters.
    Baz::class => Container::autowire(...),
    
    // Example of a simple literal value.
    'ttl-seconds' => fn () => 30,
]);

// You can spawn a child container that inherits the parent container's definitions,
// and augments/overrides them with additional definitions. This might be done, for example,
// to initialize a separate `Container` instance per request.
// Note that the *parent* container can be any instance of `Psr\Container\ContainerInterface`;
// it need not be an instance of `SubstancePHP\Container\Container`.
$container2 = Container::extend($container, [
    ServerRequestInterface::class => fn () => ServerRequestFactory::fromGlobals(),
]);

// A `Container` can be invoked to run an arbitrary callable, autowiring its parameters with 
// dependencies from the container:
$container2->run(function(

    // Parameters of named, non-scalar types will be injected based on the class/interface/enum name:
    Foo::class $foo,
    ServerRequestInterface $request,
    
    // The `SubstancePHP\Container\Inject` attribute allows specifying the dependency to
    // be injected in the given parameter. This is useful especially when the parameter is
    // of a scalar type:
    #[Inject('ttl-seconds')] int $ttl,
): void {
    // ... do stuff
});

// Similarly, if a class is autowired using Container::autowire(...), you can tell it use the Inject attribute
// to specify dependencies for parameters that cannot be inferred automatically:

public function __construct(
    Bar $bar,
    #[Inject('thing.xyz')] int $someParam,
) {
}

注意,在首次查找给定的依赖项后,它将内部缓存在容器中,下一次将返回相同的实例。这种行为与Laravel的服务容器不同,后者默认情况下每次查找都返回一个新实例。

性能

substancephp/container 的目标是在符合PSR-11容器接口的同时提供一个非常简单但灵活的API界面。

该库的目标不是达到最高的运行时性能,而是足够好,足以满足绝大多数用例——我相信它确实做到了。