edvin / hbcontainer

轻量级容器

v6.1.2 2023-08-09 11:30 UTC

README

A PSR-11轻量级依赖注入容器,适用于所有类型的项目。支持php 8.0及更高版本。

安装

使用composer

composer require edvin/hbcontainer

解析

HbContainer使用definitions来定义容器需要解析的条目。容器可以解析任何可以自行构造具有可解析依赖项的类。解析的条目默认存储为弱引用,并可以设置为单例,这将使用正常引用。

获取条目

HbContainer有三种主要方法来获取/调用条目

  1. get:解析并运行时缓存解析的值以供下一次调用。
  2. make:始终解析并返回一个新实例。
  3. call:解析提供的参数作为要调用的东西,并解析其参数。

HbContainer接受一个包含多个定义的DefinitionSource,这些定义告诉容器如何解析特定条目。不同类型包括

  1. DefinitionFactory:一个定义,包含一个闭包以返回其最终状态的项。结果被添加到单例缓存中。辅助函数:\HbLib\Container\factory
  2. DefinitionClass:一个定义,可以带参数或不带参数构建类。如果定义了任何参数,类永远不会在运行时缓存。辅助函数:\HbLib\Container\resolve。可以为此定义提供类,如果没有提供,它将假设定义ID(定义数组的索引)是类名。下面是使用示例。
  3. DefinitionReference:一个定义,用于引用另一个定义条目,您可能无法为此定义提供参数。辅助函数:\HbLib\Container\reference
  4. DefinitionValue:一个定义,用于返回一些值。该值本身可以是另一个定义。辅助函数:\HbLib\Container\value

接口

当依赖于容器时,建议依赖于提供的接口

  1. \Psr\Container\ContainerInteface:提供get方法。
  2. \HbLib\Container\FactoryInterface:提供make方法。
  3. \HbLib\Container\InvokerInterface:提供call方法。

使用方法

<?php

// Helper functions for definitions:
use function \HbLib\Container\resolve;
use function \HbLib\Container\reference;
use function \HbLib\Container\factory;

interface MyInterface {}
class MyClass implements MyInterface {}
    
class MyClass2 {
    public $value;
    
    function __construct($value) {
        $this->value = $value;
    }
}
    
class MyClass3 {
    public $value;
    
    function __construct(MyInterface $value) {
        $this->value = $value;
    }
}

class MyClass4 implements MyInterface {}
class MyManager {
    function __construct(string $type) {}
    
}

$definitions = array(
    // Factories:
    'session' => factory(function() { return true; }),
    'lol' => factory(function() { return false; }),
    'hello' => factory(function() { return null; }),
    MyManager::class => factory(function() { return new MyManager('someType'); }),
    
    MyInterface::class => resolve(MyClass::class),
    
    // Providing the class to resolve is not required when you want to resolve the ID of the definition itself.
    MyClass4::class => resolve(),
    
    'differentMyInterface' => factory(function() { return new MyClass(); }),
    
    'myClass2' => resolve(MyClass::class)->parameter('value', 'someValue'),
    
    // The ->parameter part is not required as the container can resolve the parameters
    // but it is here to display that you can tell the container to use another instance.
    'myClass3' => resolve(MyClass3::class)->parameter('value', reference('differentMyInterface')),
);

// Construct the container.
$containerBuilder = new \HbLib\Container\ContainerBuilder($definitions);
$containerBuilder->enableComiling(sys_get_temp_dir() . '/CompiledContainer.php');
$container = $containerBuilder->build();

// You can also construct the container like:
// $container = new \HbLib\Container\Container(new \HbLib\Container\DefinitionSource($definitions));

// PSR-11 method:
$container->get('session'); // => true
$container->get('lol'); // => false
$container->get('hello'); // => null

// PSR-11
$container->has('session'); // => true
$container->has('where'); // => false
$container->has('hello'); // => true

编译

容器支持将所有解析的定义编译成文件以提高性能。在生产环境中,这种优势在于容器不需要每次都查找所有参数,而是将所有定义及其依赖关系解析到一个文件中。

如何操作

必须在ContainerBuilder上启用编译,并且某些脚本必须调用writeCompiled

在您的Web应用中某处

<?php

//...
$builder = new \HbLib\Container\ContainerBuilder(new \HbLib\Container\DefinitionSource([
    //...
]));

$filePath = sys_get_temp_dir() . '/CompiledContainer.php';
$builder->enableCompiling($filePath); // important step

if (!is_file($filePath)) {
    $builder->writeCompiled();
}

$container = $builder->build();

我建议在单独的cli命令中执行ContainerBuilder::writeCompiled调用,以便错误不会影响您的客户端。

<?php
// compile_container.php

// load build just like you would in web app:
$builder = new \HbLib\Container\ContainerBuilder(new \HbLib\Container\DefinitionSource([
    //...
]));

$filePath = sys_get_temp_dir() . '/CompiledContainer.php';
$builder->enableCompiling($filePath); // important step
$builder->writeCompiled();