moro/

PHP-7 的依赖注入容器

1.4.0 2018-05-08 16:26 UTC

This package is auto-updated.

Last update: 2024-09-17 10:17:02 UTC


README

Latest Version 1.4 Build Status Software License

Container7 是一个中等大小的 PHP-7 依赖注入容器。

本包符合 PSR-1PSR-2PSR-4PSR-11。如果发现合规性问题,请通过 pull request 提交补丁。

特性:提供者、单例、工厂、参数、别名、标签、配置、序列化。

安装

通过 composer

$ composer require moro/container7

要求

  • PHP 7.1

使用

创建容器是创建 Container 实例的问题。

<?php
use Moro\Container7\Container;

$container = new Container();

与其他依赖注入容器类似,Container7 管理两种不同类型的数据:服务和参数。服务通过它们的类或别名从容器中接收。参数存储在它们的服务的 "参数" 中。

<?php
if ($container->has(Service::class)) {
    $service = $container->get(Service::class);
}

$value = $container->get('parameters')->get('key');

用于服务定义的 Service Providers。

<?php
$container->addProvider(SomeProvider::class);

Service Providers 允许您将代码或配置打包到您经常重用的包中。

Service provider

任何 Service Provider 都是一个简单的 PHP 类。服务通过返回对象实例的方法来定义。您必须将此方法的返回结果定义为类或接口。然后您可以通过该类或接口接收服务。

单例

<?php
class SomeProvider {
    function someService(): Service {
        return new Service();
    }
}

工厂

如果您想定义工厂,请添加可变参数。

<?php
class SomeProvider {
    function someService(...$arguments): Service {
        return new Service($arguments[0]);
    }
}

依赖项

当您的服务需要其他服务时,您可以将此依赖项添加到方法参数中。

<?php
class SomeProvider {
    function someService(ServiceBeta $beta): ServiceAlpha {
        return new ServiceAlpha($beta);
    }
}

记住,参数也是服务

<?php
use Moro\Container7\Parameters;

class SomeProvider {
    function someService(Parameters $parameters): Service {
        return new Service($parameters->get('key'));
    }
}

定义之后修改服务

在某些情况下,您可能希望在定义之后修改服务定义。您可以使用接收服务对象并可以返回 null 的方法。

<?php
class SomeProvider {
    function extendService(Service $service) {
        $service->value = 'value'; // example
    }
}

如果您需要替换服务实例,请使用该定义

<?php
class SomeProvider {
    function extendService(Service $service): ?Service {
        return new Decorator($service);
    }
}

您可以在这里添加依赖项,就像在工厂定义中一样。

参数

添加默认参数。

<?php
use Moro\Container7\Parameters;

class SomeProvider {
    function parameters(Parameters $parameters) {
        $parameters->set('key1', 'value1');
        $parameters->set('key2', '%key1%');
        $parameters->add('key0', ['new item']);
    }
    function someService(Parameters $parameters): Service {
        $service = new Service();
        $service->value = $parameters->get('key2');
        return $service;
    }
}

设置参数的当前值,以替换默认值。

<?php
use Moro\Container7\Container;
use Moro\Container7\Parameters;

$parameters = new Parameters(['key1' => 'value2']);
$container = new Container($parameters);
$container->addProvider(SomeProvider::class);

并使用它。

<?php
$service = $container->get(Service::class);
assert($service->value === 'value2');

别名

当您不能通过类或接口获取服务时,则必须为类、接口或方法定义别名。

<?php
use Moro\Container7\Aliases;

class SomeProvider {
    function someService(): Service {
        return new Service();
    }
    function aliases(Aliases $aliases) {
        // Add alias for unique interface in provider
        $aliases->add('kernel', Service::class);
        // or you can use method name
        $aliases->add('kernel', 'someService');
    }
}

现在您可以通过别名获取服务。

<?php
$service = $container->get('kernel');

标签

您可以通过为它们设置一个公共标签来按组对服务进行分组。

<?php
use Moro\Container7\Tags;

class SomeProvider {
    function tags(Tags $tags) {
        // Add tag for unique interface in provider
        $tags->add('someTag', ServiceAlpha::class);
        $tags->add('someTag', ServiceBeta::class);
        // or you can use method name
        $tags->add('someTag', 'getServiceAlpha');
        $tags->add('someTag', 'getServiceBeta');
    }
}

然后获取服务的集合。

<?php
$collection = $container->getCollection('someTag');

集合实现了 Iterator 接口,您可以在 foreach 中使用它。

集合操作

<?php
use Moro\Container7\Container;

$container = new Container();
$collection = $container->getCollection('A');
// Collection contains services with tag "A".
$collection = $collection->merge('B');
// Collection contains services with tags "A" or "B".
$collection = $collection->exclude('A');
// Collection contains services with tag "B" and without tag "A".
$collection = $collection->merge('B')->with('C');
// The collection contains services that are marked
// with "B" and "C" tags simultaneously.

配置

Container7 支持以 JSON 格式配置文件。您可以从这些文件创建提供者。

<?php
use Moro\Container7\Container;
use Moro\Container7\Parameters;

$configuration = Parameters::fromFile('conf.json');
$container = new Container($configuration);

配置文件可以是嵌套的。

{
  "@extends": [
    "module1.json",
    "../module2.json"
  ]
}

单例

{
  "container": {
    "singletons": [
      {
        "interface": "ServiceInterface",
        "class": "Service"
      }
    ]
  }
}

工厂

{
  "container": {
    "factories": [
      {
        "interface": "ServiceInterface",
        "class": "Service"
      }
    ]
  }
}

依赖项

{
  "container": {
    "singletons": [
      {
        "interface": "ServiceInterface",
        "class": "ServiceAlpha",
        "args": [
          "@ServiceBeta"
        ],
        "properties": {
          "value": 1
        },
        "calls": [
          {
            "method": "add",
            "args": [
              "key",
              "value"
            ]
          }
        ]
      }
    ]
  }
}

定义之后修改服务

{
  "container": {
    "extends": [
      {
        "target": "ServiceInterface",
        "calls": [
          {
            "method": "add",
            "args": [
              "key",
              "value"
            ]
          }
        ]
      }
    ]
  }
}

如果您需要替换服务实例,请使用该定义

{
  "container": {
    "extends": [
      {
        "target": "ServiceInterface",
        "class": "Decorator",
        "args": [
          "$target"
        ]
      }
    ]
  }
}

参数、别名和标签

{
  "container": {
    "parameters": {
      "key1": "value1",
      "key2": "%key1%"
    },
    "singletons": [
      {
        "aliases": ["kernel"],
        "tags": ["someTag"],
        "interface": "ServiceInterface",
        "class": "ServiceAlpha",
        "properties": {
          "value": "%key2%"
        }
      },
      {
        "tags": ["someTag"],
        "class": "ServiceBeta"
      },
      {
        "class": "Service",
        "args": [
          "$collections[someTag]"
        ]
      },
      {
        "class": "Service",
        "calls": [
          {
            "foreach": "$collections[someTag]",
            "method": "add",
            "args": ["$item"]
          }
        ]
      }
    ]
  }
}

动态服务

<?php
use Moro\Container7\Container;
use Moro\Container7\Provider;

class DynamicProvider {
    function boot(Container $container) {
        $configuration = [];
        // ... dynamic create of configuration array ...
        $container->addProvider(Provider::fromConfiguration(__METHOD__, $configuration));
    }
}

许可

MIT 许可证 (MIT)。有关更多信息,请参阅 许可证文件