dhii/containers

精选的PSR-11容器,具有实用性、简洁性和易用性。

v0.2.0-alpha1 2024-09-21 22:38 UTC

README

Continuous Integration Latest Stable Version Latest Unstable Version

详细信息

精选PSR-11容器,具有实用性、简洁性和易用性。

通用

  • CachingContainer - 一个装饰器,将缓存的关注点分离,允许缓存任何容器的值。
  • CompositeContainer - 一个由多个其他容器组成的容器。在键访问时,遍历其内部容器列表,并访问具有该键的第一个容器的该键。当需要从多个来源合并配置而不实际进行合并时很有用。
  • ProxyContainer - 一个将访问转发到1个其他容器的容器,该容器可以在构造后分配。当需要解决与容器相关的递归依赖问题,例如查找委派时很有用。
  • AliasingContainer - 一个装饰器,通过别名键提供对另一个容器的访问。当需要将不可变映射的键更改时很有用。
  • MappingContainer - 一个装饰器,使用回调在飞行中操作从另一个容器检索的值。
  • PrefixingContainer - 一个装饰器,允许通过前缀键访问另一个容器的值。也可以回退到非前缀键。当需要在键上强制执行前缀命名约定时很有用。与DeprefixingContainer相反。
  • DeprefixingContainer - 一个装饰器,允许访问具有前缀键的其他容器的值(无前缀)。例如,当需要简化遵循前缀命名约定的键时很有用。与PrefixingContainer相反。
  • MaskingContainer - 一个装饰器,可以选择性地隐藏或显示另一个容器的键。当与具有定义结构的映射一起工作时很有用。
  • PathContainer - 一个装饰器,允许通过类似于路径的键访问嵌套容器的层次结构。当需要访问从多个来源合并的配置时很有用。
  • SegmentingContainer - 一个装饰器,允许将分隔符分隔的路径样式的键作为容器层次结构访问。当在键上使用类似于路径的命名约定(如命名空间)时,可用于隔离配置段。与PathContainer相反。
  • HierarchyContainer - 一个容器,允许将任意数组的层次结构作为容器层次结构访问。在原地创建容器,并为其未来的重复使用进行缓存。
  • Dictionary - 通过容器接口访问数组,同时不牺牲迭代性。
  • DataStructureBasedFactory 允许对任意深度的数组层次结构进行递归。将数组转换为容器时特别有用,尤其是与其他装饰器一起使用。
  • SimpleCacheContainer - 一个装饰器,将 PSR-16 缓存呈现为一个可变、可清除的容器,具有固定 TTL。
  • FlashContainer - 一个装饰器,将内部存储容器中的值呈现为另一个容器,将该值复制到内存中,然后从存储中清除。
  • NoOpContainer - 一个无操作的可写可变可清除映射,不执行任何操作,并且不能有任何值。

DI

  • ServiceProvider - 一个非常简单的实现,允许快速从已知工厂和扩展的映射中创建 服务提供者
  • CompositeCachingServiceProvider - 一个服务提供者,聚合其他服务提供者的工厂和扩展。聚合的结果将被缓存,这意味着它最多只执行一次实例 - 当检索这些工厂或扩展时。
  • TaggingServiceProvider - 一个服务提供者,将标记服务聚合到具有标记名称的服务中。
  • DelegatingContainer - 一个容器,在返回值之前将调用其配置的服务提供者的工厂和扩展。如果指定了父容器,则将传递给服务定义而不是此容器。这允许 依赖项查找委托,这在从其他容器组合容器时特别有用。

示例

应用程序容器

大多数现代应用程序都使用某种类型的 DI 容器配置。以下示例演示了一个用例,其中所有配置都由不同的源组成,通过单个真实来源访问,每个请求都缓存服务。

    // Retrieve factories and extensions from respective files, and create a service provider with them
    $factories = require('factories.php');
    $extensions = require('extensions.php');
    $appProvider = new ServiceProvider($factories, $extensions);
    
    // Perhaps retrieve service providers from other modules and aggregate them
    $provider = new CompositeCachingServiceProvider([$appProvider, $moduleProviderA, $moduleProviderB]);
    
    $proxyContainer = new ProxyContainer(); // A temporary parent container for lookup delegation
    $container = new DelegatingContainer($provider, $proxyContainer); // Container with application configuration
    $appContainer = new CompositeContainer([ // The application's container
        $dbContainer, // <-- Perhaps another container with configuration from DB
        $container, // <-- The main container with merged configuration from modules
    ]);
    $appContainer = new CachingContainer($appContainer); // Add caching, so that each service definition is only invoked once
    $proxyContainer->setInnerContainer($appContainer); // Switch lookup to the application's main container, making it available in service definitions
    
    // Retrieve cached configuration aggregated from various modules and other sources, sucha as the database or a remote API
    $appContainer->get('my-service');

服务标记

您可以将服务标记到集合中。这将添加一个具有相同名称的服务,该服务将返回具有该标记的服务列表。

由于服务名称在理论上可以是任何合法字符串,但为了使其成为标记,需要对其设置一些限制,因此标记名称可以包含除空白以外的任何字符(任何与 \s 匹配的字符)。

[
    'serviceA' =>
        /** @tag letters */
        fn (): string => 'A',
    'serviceB' =>
        /**
         * @tag letters
         */
        function (): string {
            return 'B';
        },
    'serviceC' => function (ContainerInterface $c): string {
        var_dump($c->get('letters'));
    },
];

以上示例的结果如下 var_dump()

array(2) {
  [0]=>
  string(1) "A"
  [1]=>
  string(1) "B"
}

关于映射的有趣事情

映射在应用程序中非常常用,用于表示某些键值关系。我们决定 PSR-11 容器是表示映射的互操作方式的好方法。以下是您可以做的事情。

// App configuration, perhaps from a file
$config = [
  'dev' => [
    'db' => [
      'host' => 'localhost',
      'username' => 'root',
      'password' => '',
      'database' => 'my_app',
    ],
  'staging' => [
    'db' => [
      'host' => '123.abc.com',
      'username' => 'application123',
      'password' => '$*!@$T123SAfa',
      'database' => 'my_app',
    ],
  ],
];

// Can create container hierarchies of arbitrary depths from array hierarchies
$factory = new DataStructureBasedFactory(new DictionaryFactory());
// The new configuration interface
$config = $factory->createContainerFromArray($config);

// Output the DB host names for each environment
foreach ($config as $env => $envConfig) {
  echo $env . ': ' . $envConfig->get('db')->get('host') . PHP_EOL; // Print 'dev: localhost' then 'staging: 123.abc.com'
}

// Access configuration using a path
$config = new PathContainer($config, '/');
echo $config->get('staging/db/username'); // Print 'application123'

// Access dev env DB config with a 'local_' prefix
$localDbConfig = new PrefixingContainer($config->get('dev/db'), 'local_');
echo $localDbConfig->get('local_username'); // Print 'root'

// Effectively adds production DB configuration
$productionConfig = new Dictionary([
  'production' => [
    'db' => [
      'host' => 'db.myserver.com',
      'username' => 'D97rh1d0A&13',
      'password' => 'DN(Q(u3dgh3q87g3',
      'database' => 'my_app',
    ],
  ],
]);
$config = new CompositeContainer([$config, $productionConfig]);
echo $config->get('production/db/password'); // Print 'DN(Q(u3dgh3q87g3'
echo $config->get('dev/db/password'); // Print '': all of the old configuration is available on this new container

// Make production host also available as 'live_db_host' - maybe something requires it to be at that key, and not in a path
$config = new AliasingContainer($config, ['live_db_host' => 'production/db/host']);
echo $config->get('live_db_host'); // Print 'db.myserver.com'
echo $config->get('production/db/host'); // That value is still accessible by the original full path

// Isolate production DB configuration, but without the 'password' key - perhaps to be passed to the UI, or another untrusted party
$productionConfig = new MaskingContainer($config->get('production/db'), true, ['password' => false]);
echo $productionConfig->get('password'); // NotFoundException: This key does not exist for this container