atanvarno/dependency

PSR-11 依赖注入容器

2.1.0 2020-05-19 16:16 UTC

This package is auto-updated.

Last update: 2024-08-22 20:46:41 UTC


README

Software License Latest Version Build Status Coverage Status

一个基本的 PSR-11 依赖注入容器,实现了 ArrayAccess

特性

Atanvarno\Dependency 并不通过反射提供自动装配。它仅是一个基础的容器。

要求

PHP >= 8.0 是必须的,但推荐使用 PHP 的最新稳定版本。

安装

Atanvarno\Dependency 可在 Packagist 上找到,并可以使用 Composer 进行安装

$ composer require atanvarno/dependency

基本用法

<?php
use Atanvarno\Dependency\Container;
use function Atanvarno\Dependency\{entry, factory, object, value};

$container = new Container();

// Add a value to the container
$container['value ID'] = 'your value';

// Add a lazy loaded class to the container
$container['class ID'] = object(YourClass::class, ['argument1', entry('value ID')]);

// Get a value from the container
$value = $container['value ID'];
var_dump($value === 'your value'); // true

// Get a class instance from the container
$instance = $container['class ID'];
var_dump($instance instanceof YourClass::class); // true

用法

获取条目

有两种方法可以获取条目

// Using array syntax
$item1 = $container['ID'];

// Calling get()
$item2 = $container->get('ID');

从 ID 获取的条目默认情况下将是相同的实例

var_dump($item1 === $item2); // true

您可以在定义条目时指定,每次获取特定 ID 时它都将是一个新实例(参见 延迟加载条目)。

检查条目

有两种方法可以检查条目是否可用,每个都返回 bool

// Using array syntax
isset($container['ID']);

// Calling has()
$container->has('ID');

删除条目

有两种方法可以删除条目

// Using array syntax
unset($container['ID']);

// Calling delete()
$container->delete('ID');

添加条目

有几种方法可以添加条目

// Using array syntax
$container['ID'] = $entry;

// Calling set()
$container->set('ID', $entry);

$entry 可以是任何 PHP 值。当以这种方式使用时,Atanvarno\Dependency\Container 是一个简单的键值存储,与数组没有太大区别。

条目也可以定义为延迟加载。

条目也可以通过构造函数添加(参见 实例化)。

延迟加载条目

任何条目都可以定义为 延迟加载,因此它仅在访问时构建。

包含两个辅助函数,允许您定义延迟加载的条目: factory()object()

(示例使用的是 set() 方法,但数组语法也可以使用。)

您可以使用 factory() 从任何 callable 返回值

$container->set('ID', factory(
    function() {
        // ...
    }
));

您可以使用 object() 从其类名返回对象

$container->set('ID', object(ClassName::class));

factory()object() 都接受一个数组作为参数,将传递给 callable 或构造函数。这些参数可以是任何 PHP 值,也可以是其他容器条目。其他容器条目可以通过使用 entry() 函数引用

// Setting a factory
$callable = function(int $arg1, ClassName $arg2) {
    // ...
};
$container->set('ID', factory($callable, [5, entry('ClassInstance')]));

// Setting an object
class ClassName
{
    public function __construct(int arg1, OtherClass $arg2)
    {
        // ...
    }
}
$container->set('ID', object(ClassName::class, [5, entry('OtherInstance')]));

(容器本身可以使用默认条目 ID container 进行引用。如果您需要容器具有不同的条目 ID,请使用 setSelfId()。)

函数factory()object()都接受一个可选的第三个bool参数,用于确定它们返回的第一个值是否应该被注册,并在检索条目时始终返回(默认行为),或者每次都返回一个新的值(传入false)。

// A non-registered factory
$container->get('ID', factory(function(){/*...*/}, [], false));

// A non-registered object
$container->get('ID', object(ClassName::class, [], false));

设置属性和调用方法

您可能想要设置新创建对象的public属性或调用其方法,以便对其进行配置以供使用。

函数factory()object()都返回一个Definition,它提供了具有流畅接口的方法,允许您这样做。

$container->set(
    'ID',
    object(ClassName::class, [$param1, entry('param2')])
        ->method('methodName', [$param3, entry('param4')]) // Call a method with parameters
        ->property('propertyName', 'value') // Then set a property value
        ->property('otherProperty', entry('aValue')) // Then set another property
);

示例使用object(),但也可以与factory()一起使用。注意,如果factory()没有定义对象实例,这些方法将不起作用。

委托查找功能

Atanvarno\Dependency\Container实现了container-interop委托查找功能,并可以作为父容器/组合/委托和子容器使用。

要添加子容器(并将$container变为组合容器)使用addChild()

$container->addChild($otherContainerA);

后续调用将添加更多的子容器。

要添加父容器(并将$container的依赖项查找委托出去)使用setDelegate()

$container->setDelegate($otherContainerB);

后续调用将替换父容器。

流畅接口

Atanvarno\Dependency\Container提供了一个流畅接口,允许链式调用多个方法。这些方法每个都返回Container实例。

  • addChild()
  • clearCache()
  • delete()
  • get()
  • set()
  • setDelegate()
  • setSelfId()

实例化

当容器被实例化时,它可选地接受一个Definition实例的数组(由factory()object()value()返回),这些实例将被添加到容器中。此数组按条目ID索引。

$container = new Container([
    'called'
        => factory(
            function(ContainerInterface $c){return $c->get('value');},
            [entry('container')]
        ),
    'object'
        => object(
                ClassName::class,
                [entry('value'), true]
            )
            ->property('name', entry('called')
            ->method('methodName', 500),
    'value' => value('an arbitary PHP value'),
]);

您可以创建一个配置文件来返回此数组。

<?php // containerConfig.php
use function Atanvarno\Dependency\{entry, factory, object, value};

return [
    'app' =>
        object(
            AppClass::class,
            [
                entry('container'),
                entry('router'),
                entry('cache'),
                entry('logger')
            ],
            false
        ),
    'cache' =>
        object(CacheClass::class, [entry('cache config')]),
    'cache config' =>
        factory(
            function(string $configDir){return $configDir . '/cache.php';},
            [entry('config directory')]
        ),
    'config directory' => 
        value(__DIR__),
    'logger' =>
        object(LoggerClass::class, [entry('log config')])
            ->method('pushHandler', [entry('log handler'), Logger::WARNING]),
    'log config' =>
        factory(
            function(string $configDir){return $configDir . '/logger.php';},
            [entry('config directory')]
        ),
    'log handler' =>
        object(LogHandler::class, [entry('log path')]),
    'response' =>
        factory(
            function(AppClass $app) {
                return $app->getResponse($app->getRequest());
            },
            [entry('app')]
        ),
    'router' =>
        object(RouterClass::class, [entry('router config')]),
    'router config' =>
        factory(
            function(string $configDir){return $configDir . '/routes.php';},
            [entry('config directory')]
        ),
];

然后将其包含在构造函数调用中。

$container = new Container(include '../config/containerConfig.php');

缓存

Atanvarno\Dependency\Container可以使用PSR-16缓存来持久化已注册项。注意,它不持久化定义;仅持久化至少返回过一次的已注册值。

缓存对用户不可见;调用delete()get()set()将根据需要使用和更新缓存。

如果您想要清除容器的缓存,请使用clearCache()

// Clears the container's cache; other values stored in the cache are untouched
$container->clearCache();

构造函数接受缓存作为其第二个参数,以及用作缓存的可选键的第三个参数(默认为container)。

/** @var CacheInterface $cache PSR-16 cache. */
$cache = /* ... */ ;
$container = new Container([], $cache, 'container-cache-key');

构造函数还接受一个entry(),它指向第一个参数中定义的缓存,因此缓存实例可以由容器本身加载。

$container = new Container(
    ['cache' => object(CacheClass::class)],
    entry('cache'),
    'cache-key'
);

异常

所有抛出的异常都实现了PSR-11ContainerExceptionInterface

完整API

请参阅API