mouf/container-installer

此包包含一个PHP依赖注入容器检测和聚合器。想法是每个composer包可能有潜在的一个DI容器,并将所有这些容器聚合到一个“根”容器中。

安装: 283

依赖: 1

建议者: 0

安全: 0

星标: 1

关注者: 19

分支: 0

开放问题: 0

类型:composer-plugin

1.0.x-dev 2015-02-06 12:50 UTC

This package is auto-updated.

Last update: 2024-09-15 04:36:41 UTC


README

此项目是在开发ContainerInterop项目期间作为概念验证开发的测试项目。

总体目标

最终目标是允许应用开发者轻松创建一个“根容器”,该容器可以自动检测并添加其他包中包含的容器,形成一个可由应用使用的全局复合容器。

与传统思考方式相比,这是一个范式转变。

在“经典”应用中,添加到应用中的包可能会向主且唯一的DI容器添加新的实例。这是SF2包、ZF2模块或Mouf2包所做的。

使用此方法,每个包都提供了一个包含实例的DI容器。DI容器被添加到一个全局容器中,并对其进行查询。

关于此包

此包的目标是简单地为应用开发者提供一种检测在使用的Composer包中可能声明的DI容器的方法。

此项目在Composer“安装”步骤中添加了一个额外的步骤,在Composer将自动加载器导出之后进行。Container-Installer将扫描所有composer.json文件,并查找类似以下部分的内容:

{
	"extra": {
		"container-interop": {
			"container-factory": "My\\ContainerFactory::getContainer"
		}
	}
}

此部分实际上声明了可以打包在包中的容器工厂。

“container-factory”参数必须指向一个函数或静态方法,该方法返回容器。

以下是一个示例实现

class ContainerFactory {
	private static $container;

	/**
	 * This method is returning a configured container
	 *
	 * @param ContainerInterface $rootContainer
	 * @return ContainerInterface
	 */
	public static function getContainer(ContainerInterface $rootContainer) {
		if (!$this->container) {
			// Delegate dependencies fetching to the root container.
			$this->container = new Picotainer([
				"hello" => function(ContainerInterface $container) {
					return array('hello' => $container->get('world'));
				}
			], $rootContainer);
		}
		return $this->container;
	}
}

关于此代码的简要说明:我们提供了一个Picotainer容器。Picotainer是一个与ContainerInterop项目完全兼容的简约容器。

重要:工厂需要一个强制参数:$rootContainer。如果您的容器中包含外部依赖(不属于容器的依赖),则您的容器需要能够将依赖项获取委托给$rootContainer。例如,如果将另一个容器作为构造函数的第一个参数传递,则PimpleInterop可以委托依赖项获取。

注意:您的包不必要求mouf/container-installer包。这很棒,因为如果其他容器聚合器遵循相同的约定(在composer.json的额外部分中引用工厂代码),则可以轻松实现许多不同的根容器实现(可能每个框架一个)。

如何在项目中使用根容器?

此包将在项目根目录下创建一个containers.php文件。此containers.php文件将包含以下形式的容器列表

<?php
return [
    [
        'name' => '__root___0',
        'description' => 'Container number 0 for package __root__',
        'factory' => My\ContainerFactory::getContainer,
        'enable' => true
    ],
];

请注意,开发者可以使用“enable”属性手动启用或禁用包。

之后,使用该文件的权限就交给了应用开发者。

使用Acclimate的CompositeContainer,使用方式可能如下

use Acclimate\Container\CompositeContainer;

// Let's create a composite container
$rootContainer = new CompositeContainer();

// Let's get the containers list
$container_descriptors = require 'containers.php';

// Let's add containers to the root container.
foreach ($container_descriptors as $descriptor) {
    if (descriptor['enable']) {
        $container = $descriptor['factory']($rootContainer);
        $rootContainer->addContainer($container);
    }
}

$myEntry = $rootContainer->get('myEntry');

允许的语法

以下语法都适用于在 composer.json 中声明容器工厂。

通过 回调 声明容器工厂。

{
	"extra": {
		"container-interop": {
			"container-factory": "My\\ContainerFactory::getContainer"
		}
	}
}

通过回调声明 容器工厂数组

{
	"extra": {
		"container-interop": {
			"container-factory": [
				"My\\ContainerFactory1::getContainer",
				"My\\ContainerFactory2::getContainer",
				"My\\ContainerFactory3::getContainer"
			]
		}
	}
}

声明容器工厂 描述符(它包含有关工厂的附加数据)。

{
	"extra": {
		"container-interop": {
			"container-factory": {
				"name": "a unique name for the factory",
				"description": "a description of what the factory does",
				"factory": "My\\ContainerFactory::getContainer"
			}
		}
	}
}

注意:描述符的所有参数都是可选的,除了“工厂”部分。

声明 容器工厂描述符数组

{
	"extra": {
		"container-interop": {
			"container-factory": 
			[{
				"name": "a unique name for the factory",
				"description": "a description of what the factory does",
				"factory": "My\\ContainerFactory::getContainer"
			},
			{
				"name": "a unique name for another factory",
				"description": "a description of what the factory does",
				"factory": "My\\ContainerFactory2::getContainer"
			}]
		}
	}
}

优点

每个包提供其容器。包不依赖于应用中使用的 DI 容器。这样,我们可以提供无框架依赖的包。

缺点

复合控制器的经典实现可能会导致性能下降。我们需要考虑提高复合容器(可能通过条目映射、将条目映射到其相关容器)性能的方法。

关于其他项目

这不是唯一一个在“每个包一个容器”范式上工作的项目。@mnapoli 的 FrameworkInterop 项目 也在走相同的路线(尽管其范围更广)。

关于性能

当前 RootContainer 的实现依赖于 Acclimate 的 CompositeContainer。这是一个概念验证,没有在性能方面做出努力。应用中的容器越多,性能应该越低(线性)。

但这并不意味着性能无法提高。有许多可能的策略可以改善性能,例如创建所有条目及其相应容器的映射。这超出了当前项目的范围。